2010-06-17 14 views
6

Je suis un appareil de test d'une interface ICustomerRepository utilisé pour récupérer des objets de type Customer.Quel est le but de l'unité de test d'un référentiel d'interface

  • En tant que test unitaire, quelle valeur gagne-t-on en testant le ICustomerRepository de cette manière?
  • Dans quelles conditions le test ci-dessous échouerait-il?
  • Pour les tests de cette nature est-il conseillé de faire des tests que je sais devrait échouer? à savoir chercher id 4 quand je sais que je ne l'ai placé 5 dans le dépôt

Je suis probablement manque quelque chose d'évident, mais il semble que les tests d'intégration de la classe qui implémente ICustomerRepository sera de plus de valeur.

[TestClass] 
public class CustomerTests : TestClassBase 
{ 
    private Customer SetUpCustomerForRepository() 
    { 
     return new Customer() 
     { 
      CustId = 5, 
      DifId = "55", 
      CustLookupName = "The Dude", 
      LoginList = new[] 
      { 
       new Login { LoginCustId = 5, LoginName = "tdude" }, 
       new Login { LoginCustId = 5, LoginName = "tdude2" } 
      } 
     }; 
    } 

    [TestMethod] 
    public void CanGetCustomerById() 
    { 
     // arrange 
     var customer = SetUpCustomerForRepository(); 
     var repository = Stub<ICustomerRepository>(); 

     // act 
     repository.Stub(rep => rep.GetById(5)).Return(customer); 

     // assert 
     Assert.AreEqual(customer, repository.GetById(5)); 
    } 
} 

Base de test de classe

public class TestClassBase 
{ 
    protected T Stub<T>() where T : class 
    { 
     return MockRepository.GenerateStub<T>(); 
    } 
} 

ICustomerRepository et IRepository

public interface ICustomerRepository : IRepository<Customer> 
{ 
    IList<Customer> FindCustomers(string q); 
    Customer GetCustomerByDifID(string difId); 
    Customer GetCustomerByLogin(string loginName); 
} 

public interface IRepository<T> 
{ 
    void Save(T entity); 
    void Save(List<T> entity); 
    bool Save(T entity, out string message); 
    void Delete(T entity); 
    T GetById(int id); 
    ICollection<T> FindAll(); 
} 

Répondre

5

Règle n ° 1 des tests:

savoir ce que le but de votre test est et ce qu'il essaie de prouver avant de l'écrire. Si vous ne savez pas ce qu'il prouve, alors c'est inutile :)

Comme les autres affiches l'ont dit correctement, vous êtes en train de cogner une interface et ensuite d'appeler le talon - cela ne prouve pas si votre production le code fonctionne.

Qu'est-ce qu'un bout?

Les tronçons sont utilisés pour fournir des valeurs prédéfinies pour piloter certains aspects de la classe testée. Par exemple. Supposons que vous avez un CustomerService qui a une instance de type ICustomerRepository. Si vous vouliez voir que le CustomerService pouvait gracieusement gérer un cas d'erreur lorsque le référentiel était vide, vous inverseriez la méthode GetCustomerById de ICustomerRepository pour retourner rien/null/lancer une exception, puis vérifiez que la méthode CustomerService a bien fait (par exemple retourner un résultat client non trouvé).

I.e. le talon est juste un collaborateur qui vous aide à atteindre la condition particulière/le comportement d'intérêt. Nous testons CustomerService et le ICustomerRepository bloqué nous aide simplement à atteindre notre objectif.

Vous n'êtes pas le premier à poser cette même question :). Je conseille habituellement aux développeurs de hand-roll their test doubles at first. Cela aide à comprendre toutes les interactions et ce que le framework est en train de faire pour vous.

4

Interfaces, par définition, ne sont que des contrats, donc il n'y a pas de code à tester. Vous voulez écrire des tests unitaires par rapport aux implémentations concrètes de l'interface, car c'est là que le code d'exécution actuel vit.

S'il n'y a pas d'implémentation concrète de l'interface et que vous ne faites que vous moquer d'une implémentation concrète, votre test unitaire est basé sur un simulacre. Ce n'est pas vraiment de grande valeur.

6

Il se peut que je manque quelque chose, mais il semble que chaque aspect de votre test soit mocké?

En règle générale, vous ne faites que simuler les objets qui ne sont pas essentiels au test. Dans ce cas, vous pouvez utiliser ce référentiel comme source pour une fonction dont vous vous attendez à faire quelque chose avec le référentiel pour récupérer le client n ° 5 et y effectuer une opération. Par exemple, vous pouvez créer une maquette d'un référentiel client afin de pouvoir appeler une méthode qui vérifie la connexion d'un utilisateur. Vous utiliseriez votre référentiel factice pour empêcher votre test d'unité de s'appuyer sur une source de données réelle, et non pour tester votre référentiel fictif.

2

Votre test n'a aucun sens pour moi. Vous testez si un stub préprogrammé renvoie les valeurs que vous lui fournissez. Vous ne testez aucun code réel.

Suivez la réponse de DCP. Une interface est une déclaration de méthodes. Vous devriez tester les implémentations de ceux-ci.

+0

Comment? Partout où je lis, on nous apprend à simuler une interface pour notre test unitaire. Comment testons-nous une implémentation concrète? Je pensais que cela devrait être évité à ma compréhension. Pouvez-vous donner un exemple? Je vous remercie! – Stack0verflow

+1

Une interface est une spécification, une déclaration, pas un code que vous pouvez exécuter (et donc tester). Vous implémentez cette spécification dans des classes concrètes, c'est le code que vous allez exécuter et tester. Vous pouvez utiliser un simulacre pour implémenter une interface, pour vous aider à tester un autre code qui dépend des objets qui implémentent cette interface. Vous ne "testez pas une interface", vous testez que les implémentations de cette interface sont correctes, en appelant des méthodes d'interface sur ces implémentations ("test contre l'interface"). –

+1

Exemple stupide: Une interface 'Eater' pour les choses qui' eat', implémentée par 'Dog' et appelée par' Master' dans une méthode 'feed (Eater pet)'. Lorsque vous testez 'Dog', vous testerez son implémentation de l'interface' Eater' en appelant 'eat' sur une instance de chien et voyez par ex. que le chien gagne du poids. Lorsque vous testez la méthode 'Master's' feed() ', vous créez un simulacre' Eater', passez-le à cette méthode et vérifiez que 'eat' a été appelé. –