2016-05-16 9 views
0

Я читал о TDD, и я видел много сообщений о том, чтобы не делать транзакций с базой данных, потому что «одиночный изолированный блок кода без зависимостей».TDD Вставка в базу данных

Итак, теперь у меня есть немного дилеммы - я хочу проверить, действительно ли работает мой метод уровня обслуживания AddNewStudent. Этот метод переходит в мой DbContext, а затем добавляет новую запись в базу данных. Если операции с базами данных не рекомендуются для TDD, то как еще я могу протестировать метод AddNewStudent, кроме как просто проверить мое приложение в браузере?

public class StudentManager : ManagerBase 
{ 
    internal StudentManager() { } 

    public Student AddNewStudent(string fName, string lName, DateTime dob) 
    { 
     // Create a student model instance using factory 
     var record = Factories.StudentFac.CreateOne(fName, lName, dob); 

     DbContext.Students.Add(record); 
     DbContext.SaveChanges(); 

     return record; 
    } 
} 

И мой тест выглядит так

[TestMethod] 
public void StudentManager_AddNewStudent_Test() 
{ 
    var fName = "Ryan"; 
    var lName = "Rigil"; 
    var dob = DateTime.Parse("3/1/2006"); 

    var student = Managers.StudentManager.AddNewStudent(fName, lName, dob); 

    Assert.AreEqual(fName, student.FirstName); 
    Assert.AreEqual(lName, student.LastName); 
    Assert.AreEqual(dob.ToShortDateString(), student.DoB.ToShortDateString()); 
} 
+1

Создайте абстракцию своего DbContext, который вы можете объединить в своих модульных тестах, чтобы проверить тестируемый метод. – Nkosi

+0

Откуда берется «DbContext»? Это Entity Framework? В какой единичной структуре тестирования вы используете (т. Е. NUnit)? Можем ли мы увидеть какой-либо пример кода, показывающий, что вы хотите издеваться/тестировать? –

+0

Добавлен пример кода выше –

ответ

1

Ваш StudentManager имеет зависимости погребенные внутри, которые делают его трудно проверить. Рассмотрим реструктуризацию вашего дизайна, чтобы обеспечить лучшую возможность тестирования.

Глядя на StudentManager были получены следующие предположения ...

//An assumed abstraction of the ManagerBase 
public abstract class ManagerBase { 
    public ManagerBase(IDbContext dbContext, IFactory factories) { 
     DbContext = dbContext; 
     Factories = factories; 
    } 
    public IDbContext DbContext { get; private set; } 
    public IFactory Factories { get; private set; } 
} 

//An abstraction of what the unit of work would look like 
public interface IDbContext { 
    //student repository 
    DbSet<Student> Students { get; } 
    //...other repositories 
    int SaveChanges(); 
} 

//Just an example of the Student Factory. 
public interface IModelFactory<T> where T : class, new() { 
    T Create(Action<T> configuration); 
} 

public interface IFactory { 
    IModelFactory<Student> StudentFac { get; } 
    //...other factories. Should try to make your factories Generic 
} 

При том, что целевой класс refactors к ...

public class StudentManager : ManagerBase { 
    public StudentManager(IDbContext dbContext, IFactory factories) : base(dbContext, factories) { } 

    public Student AddNewStudent(string fName, string lName, DateTime dob) { 
     // Create a student model instance using factory 
     var record = Factories.StudentFac.Create(r => { 
      r.FirstName = fName; 
      r.LastName = lName; 
      r.DoB = dob; 
     }); 

     base.DbContext.Students.Add(record); 
     base.DbContext.SaveChanges(); 

     return record; 
    } 
} 

Хотя это может выглядеть, сколько это будет в значительной степени поможет проверяемость вашего кода.

насмешливые рамки, как Moq теперь могут быть использованы для создания поддельной версии доступа к базе данных и фабрики ...

[TestMethod] 
public void StudentManager_Should_AddNewStudent() { 
    //Arrange: setup/initialize the dependencies of the test 
    var fName = "Ryan"; 
    var lName = "Rigil"; 
    var dob = DateTime.Parse("3006-01-03"); 

    //using Moq to create mocks/fake of dependencies 
    var dbContextMock = new Mock<IDbContext>(); 

    //Extension method used to create a mock of DbSet<T> 
    var dbSetMock = new List<Student>().AsDbSetMock(); 
    dbContextMock.Setup(x => x.Students).Returns(dbSetMock.Object); 

    var factoryMock = new Mock<IFactory>(); 
    factoryMock 
     .Setup(x => x.StudentFac.Create(It.IsAny<Action<Student>>())) 
     .Returns<Action<Student>>(a => { 
      var s = new Student(); 
      a(s); 
      return s; 
     }); 

    //this is the system/class under test. 
    //while this is being created manually, you should look into 
    //using DI/IoC container to manage Dependency Injection 
    var studentManager = new StudentManager(dbContextMock.Object, factoryMock.Object); 

    //Act: here we actually test the method 
    var student = studentManager.AddNewStudent(fName, lName, dob); 

    //Assert: and check that it executed as expected 
    Assert.AreEqual(fName, student.FirstName); 
    Assert.AreEqual(lName, student.LastName); 
    Assert.AreEqual(dob.ToShortDateString(), student.DoB.ToShortDateString()); 
} 

Для производства вы можете создавать собственные реализаций интерфейсов и ввести их в классы которые зависят от них. Этот ответ полностью основан на примере, который вы указали в своем сообщении. Потратьте некоторое время на понимание используемых понятий, а также сделайте еще несколько исследований в Интернете. Затем вы можете применить эти концепции с остальной частью своего проекта по мере продвижения с помощью TDD.

+0

Быстрый вопрос ... В моих предыдущих проектах я бы использовал абстрактное UoW, но поскольку этот будет использовать файл EDMX, требуется ли абстракция UoW? Разве это не дублированная работа? –

+0

Еще одна причина, по которой я хочу использовать фабрики, заключается в том, что всякий раз, когда я создаю экземпляр модели (в данном случае студент), мне не нужно угадывать, какие свойства требуются или нет. С действием на самом деле нет ничего, что помешало бы мне создать экземпляр студента без имени и фамилии - студент с только DoB. –

+0

Это был просто пример, основанный на коде в исходном посте.Вы все равно можете создать свой собственный метод, который будет делать то, что вы намеревались изначально. – Nkosi

Смежные вопросы