2008-08-07 26 views
5

Mon dernier désastre trébucher à travers la moquerie n'est pas que je dois pousser les résultats dans un objet simulé de IEnumerable<T>.Comment vous moquez-vous correctement d'un IEnumerable <T>?

est ici un échantillon (démonstration seulement IEnumerable<T>, pas vraiment bon test basé sur une interaction!):

using System; 
using System.Collections.Generic; 
using Rhino.Mocks; 
using MbUnit.Framework; 

[TestFixture] 
public class ZooTest 
{ 
    [Test] 
    public void ZooCagesAnimals() 
    { 
     MockRepository mockery = new MockRepository(); 

     IZoo zoo = new Zoo(); 

     // This is the part that feels wrong to create. 
     IList<IAnimal> mockResults = mockery.DynamicMock<IList<IAnimal>>(); 
     IAnimal mockLion = mockery.DynamicMock<IAnimal>(); 
     IAnimal mockRhino = mockery.DynamicMock<IAnimal>(); 

     using (mockery.Record()) 
     { 
      Expect.Call(zoo.Animals) 
       .Return(mockResults) 
       .Repeat.Once(); 
     } 

     using (mockery.Playback()) 
     { 
      zoo.CageThe(mockLion); 
      zoo.CageThe(mockRhino); 

      Assert.AreEqual(mockResults, new List<IAnimal>(zoo.Animals)); 
     }  
    } 
} 


public class Zoo : IZoo 
{ 
    private IList<IAnimal> animals = new List<IAnimal>(); 

    public void CageThe(IAnimal animal) 
    { 
     animals.Add(animal); 
    } 

    public IEnumerable<IAnimal> Animals 
    { 
     get 
     { 
      foreach(IAnimal animal in animals) 
      { 
       yield return animal; 
      } 
     } 
    } 
} 

public interface IAnimal 
{ 
} 

public interface IZoo 
{ 
    IEnumerable<IAnimal> Animals { get;} 
    void CageThe(IAnimal animal); 
} 

Je n'aime pas comment je l'ai eu à travailler pour les raisons suivantes:

  • Consommer les résultats IEnumerable<IAnimal> en IList<IAnimal> - parce que je comprends cela met les résultats à vérifier sur le tas.
  • Définition du contenu des résultats - que je comprends également; mais mon point principal est de tester que Zoo.Animals retourne IEnumerable<IAnimal>, et encore mieux, qu'il utilise yield return à l'intérieur.

Des suggestions pour ce faire mieux ou plus simple?

Editer: J'essaie de déterminer la façon optimale de tester l'interaction entre IEnumerable<T> et tout ce que j'utilise. Je n'essaie pas de tester que Zoo peut contenir des animaux, plutôt que Zoo expose comme IEnumerable<IAnimal>, et que yield return s'habitue également.

+1

Rétrospectivement, il s'agit d'une question ** TERRIBLE **. Essayer d'obtenir des votes pour fermer –

Répondre

4

Si vous testez l'implémentation , pourquoi essaieriez-vous de le rogner en premier lieu? Pourquoi ne pas simplement CageThe (IAnimal), puis vérifier que Animals contient IAnimal? Je vois que vous vous moquez des IAnimals, vu qu'apparemment vous n'avez pas encore d'animaux concrets avec lesquels jouer, mais pourquoi ne pas en faire des stubs, parce que vous ne vous attendez évidemment pas à autre chose? eux en dehors d'être mis dans la liste?

Edit: Quelque chose à peu près le long de ces lignes (non testé, pourrait ne pas compiler, peut manger votre chien, etc.):

[TestFixture] 
public class ZooTest 
{ 
    [Test] 
    public void ZooCagesAnimals() 
    { 
     MockRepository mockery = new MockRepository(); 

     IAnimal mockLion = mockery.Stub<IAnimal>(); 
     IAnimal mockRhino = mockery.Stub<IAnimal>(); 

     IZoo zoo = new Zoo(); 

     zoo.CageThe(mockLion); 
     zoo.CageThe(mockRhino); 

     List<IAnimal> animals = new List<IAnimal>(zoo.Animals); 
     Assert.IsTrue(animals.Contains(mockLion)); 
     Assert.IsTrue(animals.Contains(mockRhino)); 
    } 
} 
3

Je ne vois pas comment vous vous attendez à mettre en place des attentes Mock sur un objet qui n'est pas un faux pour commencer. En outre, vous configurez l'attente de renvoyer un IList qui n'est pas vraiment ce qui se passe lorsque le compilateur génère un itérateur.

Si vous voulez tester spécifiquement l'itérateur, vous devriez probablement

Assert.IsNotNull(zoo.Animals); 

Et puis vérifiez que le recenseur fait sur toutes énumère les choses que vous avez ajoutés au zoo. C'est ce que j'allais faire là-bas. :)

Je ne sais pas s'il est même possible de tester si le retour de rendement est appelé, car le rendement de rendement est juste du sucre syntaxique pour un IEnumerable généré par le compilateur. Par exemple, appeler

zoo.Animals.GetEnumerator(); 

ne signera pas du code que vous avez écrit dans le recenseur. La première fois que cela se produit est sur le premier appel à IEnumerator.MoveNext(); Maintenant, si vous essayez de tester l'interaction entre le zoo concret et le IEnumerable contenu par ce zoo, vous devriez faire de IEnumerable un champ sur Zoo et injecter un IEnumerable faux à ce champ au lieu d'implémenter un IEnumerable concret directement dans Zoo.

J'espère que cela vous aidera.