Проблема с использованием Moq в модульных тестах - PullRequest
2 голосов
/ 06 декабря 2010

Я изучал использование фиктивных объектов в модульном тестировании и пробовал среду Moq для .NET.У меня возникают некоторые проблемы при попытке протестировать метод уровня сервиса, который возвращает объект домена из базы данных.

Вот мои настройки:

    [SetUp]
    public void DoSetupTasks()
    {
        mockDao = new Mock<IHibernateDao>();
        _hibernateService = new HibernateService(mockDao.Object);
        mockDomainObject = new Mock<DomainBase>();
        dmBase = new DomainBase()
        {
            Id = 5
        };
    }

Вот модульный тест IУ меня проблемы с.Метод FindById() возвращает объект DomainBase на основе заданного идентификатора и типа.

    [Test]
    public void TestFindById()
    {
        mockDomainObject.Setup(dmb => dmb.Id.Equals(It.IsAny<long>())).Returns(true);
        mockDao.Setup(dao => dao.FindById(
            It.IsAny<long>(),
            It.IsAny<Type>()
        )).Returns(mockDomainObject.Object);

        _hibernateService.FindById(dmb.Id, typeof(DomainBase));
        mockDomainObject.VerifySet(dmb => dmb.Id = dmBase.Id);
    }

Когда я запускаю модульный тест, выдается следующее исключение:

Exception: Invalid setup on a non-virtual (overridable in VB) member: dmb => dmb.Id.Equals(It.IsAny<Int64>())

Признаюсь, я довольно незнаком с фреймворком,Я пытался следовать некоторым учебникам, но мне не удалось понять это.

1 Ответ

6 голосов
/ 07 декабря 2010

Попробуйте что-то вроде этого:

[Test]
public void TestFindById() {

    const int TEST_ID = 5;
    // Configure your mock DAO to return a real DomainBase 
    // when FindById is called.
    mockDao
        .Setup(dao => dao.FindById(TEST_ID, It.IsAny<Type>())
        .Returns(new DomainBase() { Id = TEST_ID });

    var domainObject = _hibernateService.FindById(TEST_ID , typeof(DomainBase));

    // Make sure the returned object is a DomainBase with id == TEST_ID 

    Assert.IsEqual(TEST_ID , domainObject.Id);
    Assert.IsInstanceOf<DomainBase>(domainObject);

    // and verify that your mock DAO was called with the same argument passed to 
    // your NHibernate service wrapper:
    mockDao.VerifyAll();
}

Вам не нужно издеваться над объектами вашего домена - вам, как правило, лучше издеваться над слоем данных и службами, а затем передавать реальные объекты домена (содержащие образец/ test data) между вашим тестируемым логическим кодом и слоями поддельных сервисов.

EDIT: для тестирования методов сохранения и удаления вы захотите сделать что-то подобное.Обратите внимание, как мы используем метод Callback () библиотеки Moq для запуска некоторого кода при вызове метода mock, и в рамках этого обратного вызова мы утверждаем, что объект, переданный нашему методу, был объектом, который мы ожидали:

[Test]
public void TestSaveDomainBase() {

    const int OBJECT_ID = 5;

    mockDao
      .Setup(dao => dao.Save(It.IsAny<DomainBase>()))
      .Callback((DomainBase d) => {
         // Make sure the object passed to Delete() was the correct one
         Assert.AreEqual(OBJECT_ID, d.ID);
      });

    var objectToSave = new DomainObject() { Id = OBJECT_ID };

    _hibernateService.Save(objectToDelete);

    mockDao.VerifyAll();
}


[Test]
public void TestDeleteDomainBase() {

    const int OBJECT_ID_TO_DELETE = 5;

    mockDao
      .Setup(dao => dao.Delete(It.IsAny<DomainBase>()))
      .Callback((DomainBase d) => {
         // Make sure the object passed to Delete() was the correct one
         Assert.AreEqual(OBJECT_ID_TO_DELETE, d.ID);
      });

    var objectToDelete = new DomainObject() { Id = OBJECT_ID_TO_DELETE };

    _hibernateService.Delete(objectToDelete);


    mockDao.VerifyAll();
}
...