2010-12-06 50 views
2

J'ai étudié l'utilisation d'objets factices dans les tests unitaires et essayé le framework Moq pour .NET. Je rencontre des problèmes lors de la tentative de test d'une méthode de couche de service qui renvoie un objet de domaine à partir d'une base de données.Problème lors de l'utilisation de Moq dans les tests unitaires

Voici ma configuration:

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

Voici le test unitaire je rencontre des problèmes avec. La méthode FindById() renvoie un objet DomainBase basé sur un ID et un type donnés.

[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); 
    } 

Quand je lance le test unitaire, il jette l'exception suivante:

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

Je l'avoue, je suis assez familier avec le cadre. J'ai essayé de suivre quelques tutoriels, mais je n'ai pas réussi à le comprendre.

Répondre

6

Essayez quelque chose comme ceci:

[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(); 
} 

Vous ne devriez pas avoir à se moquer de vos objets de domaine - vous êtes généralement mieux se moquant votre couche de données et de services et en faisant passer des objets réels de domaine (contenant l'échantillon/données de test) entre votre code logique sous test et vos couches de service simulées.

EDIT: Pour tester les méthodes d'enregistrement et de suppression, vous devez effectuer une opération similaire. Notez comment nous utilisons la méthode Callback() de la bibliothèque Moq pour exécuter du code lorsque la méthode mock est appelée, et dans ce rappel, nous affirmons que l'objet passé à notre méthode était l'objet attendu:

[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(); 
} 
+0

Merci! Je vais essayer d'en faire un compte-rendu demain, mais si je me fie uniquement à votre code, c'est beaucoup plus logique maintenant. –

+0

Votre exemple a bien fonctionné. Merci encore, Dylan. Une autre question: comment pourriez-vous écrire un test qui vérifierait la persistance d'un objet de domaine dans une base de données ou la suppression d'un objet? –

+0

Voir édition. C'est un peu le même principe mais en sens inverse - vous créez votre objet domaine, passez le dans la méthode de service, puis vérifiez dans votre simulation (via un rappel) que la couche de service passe les bons objets aux bonnes méthodes sur votre DAO. –