Имитация UnitOfWork с помощью Moq и EF 4.1

Я прорабатываю образец Contoso для некоторой практики TDD, и мои тесты по поиску учащихся проходят успешно.

Мой тест на создание нового студента терпит неудачу (хотя фактический код работает), поскольку я считаю, что DBContext не издевается.

Что я должен реорганизовать, чтобы пройти этот тест?

Тест не проходит так:

Contoso.Tests.Controllers.StudentControllerTest.Create_HttpPost_Should_Save_New_Student: Ожидается: 9 Но было: 8

Вот конкретный UnitOfWork

public class UnitOfWork : IUnitOfWork
{
    private SchoolContext context = new SchoolContext();

    private IStudentsRepository studentsRepository;

    private bool disposed = false;

    public IStudentsRepository StudentsRepository
    {
        get
        {
            if (this.studentsRepository == null)
            {
                this.studentsRepository = new StudentsRepository(context);
            }
            return studentsRepository;
        }
    }


    public void Save()
    {
        context.SaveChanges();
    }


    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

СтудентКонтроллер

public class StudentController : Controller
{
    private IUnitOfWork _unitOfWork;

    public StudentController(IUnitOfWork unitOfWork)
    {
        this._unitOfWork = unitOfWork;
    }

...

    [HttpPost]
    public ActionResult Create(Student student)
    {
        if (ModelState.IsValid)
        {
            _unitOfWork.StudentsRepository.Add(student);
            _unitOfWork.StudentsRepository.Save();

            return RedirectToAction("Details", new { id = student.StudentID });
        }

        return View(student);
    }

...
}

Вот где я издеваюсь над IUnitOfWork

    public static IUnitOfWork MockUnitOfWork(List<Student> students)
    {
        var mockUnitOfWork = new Mock<IUnitOfWork>();

        mockUnitOfWork.Setup(x => x.StudentsRepository.Students()).Returns(students.AsQueryable());

        return mockUnitOfWork.Object;
    }

Вот неудачный тест

private IUnitOfWork unitOfWork = UnitTestHelpers.MockUnitOfWork(testData);
...



    [Test]
    public void Create_HttpPost_Should_Save_New_Student()
    {
        // Arrange
        var studentsCount = unitOfWork.StudentsRepository.Students().Count();
        var controller = new StudentController(unitOfWork);
        var student = Fakes.FakeStudentsData.CreateStudent();

        // Act
        var result = controller.Create(student);

        // Assert
        Assert.AreEqual(studentsCount+1, unitOfWork.StudentsRepository.Students().Count());
        Assert.IsInstanceOf(typeof(RedirectToRouteResult), result);
    }

person Nicholas Murray    schedule 24.07.2011    source источник
comment
Не могли бы вы предоставить исходники StudentController? Какое исключение выбрасывается?   -  person Restuta    schedule 25.07.2011
comment
@Restuta тест просто не проходит - исключений нет.   -  person Nicholas Murray    schedule 25.07.2011
comment
Хорошо, какое из двух утверждений неверно?   -  person Restuta    schedule 25.07.2011
comment
Assert.AreEqual — Ожидается: 9, но было: 8   -  person Nicholas Murray    schedule 25.07.2011
comment
Извините, что поднимаю этот вопрос, но где этот пример кода? Я пишу свое собственное приложение, чьи контроллеры также реализуют UnitOfWork, и мне интересно, следует ли мне внедрить единицу работы в мои контроллеры и как это все работает (ради модульного тестирования моих контроллеров в будущем). Спасибо!   -  person Killnine    schedule 26.06.2012
comment
asp.net/mvc/tutorials/getting-started- with-ef-using-mvc и nicholascontoso.codeplex.com   -  person Nicholas Murray    schedule 27.06.2012


Ответы (1)


Похоже, что метод Add для StudentRepository также необходимо смоделировать. Я не уверен, что синтаксис правильный, но попробуйте следующее:

public static IUnitOfWork MockUnitOfWork(List<Student> students)
{
    var mockUnitOfWork = new Mock<IUnitOfWork>();

    mockUnitOfWork.Setup(x => x.StudentsRepository.Students()).Returns(students.AsQueryable());
    mockUnitOfWork.Setup(x => x.StudentsRepository.Add(It.IsAny<Student>())).Callback<Student>((s) => students.Add(s));

    return mockUnitOfWork.Object;
}
person John Allers    schedule 25.07.2011
comment
Благодарность! что проходит тест. Есть ли способ увеличить идентификатор при добавлении нового ученика? - person Nicholas Murray; 26.07.2011
comment
Возможно, вы сможете расширить обратный вызов, например: ...Обратный вызов‹Студент›((s) =› { student.Add(s); s.ID = student.Select(x =› x.ID).Max () + 1;}); - person John Allers; 26.07.2011
comment
Прохладный. Я попробую это сегодня вечером, думал о перенаправлении на страницу сведений после добавления нового ученика, поэтому мне нужно будет передать идентификатор. Есть ли хороший учебник в Интернете, чтобы научиться издеваться? - person Nicholas Murray; 26.07.2011
comment
Moq QuickStart довольно хорош (code.google.com/p/moq/wiki/QuickStart) и другие ссылки оттуда. - person John Allers; 26.07.2011
comment
О, конечно! Был там раньше, но теперь это намного более актуально. - person Nicholas Murray; 26.07.2011