2011-10-17 3 views
2

Je me demande comment vérifier qu'une méthode renvoie un conteneur encapsulant une collection qui est l'agrégat de plusieurs autres conteneurs renvoyés par des objets fantaisie. Autrement dit, il contient tous les éléments des conteneurs individuels. J'ai d'autres tests qui vérifient le conteneur 'works' (add/addAll/etc), donc je sais que ça marche, mais je ne suis pas sûr de savoir comment ça se passe avec le test ci-dessous 'createsRoadUsersAccordingToAllAddedCreators'.Objets moqueurs qui encapsulent des collections

J'ai une classe RoadUserCreationDaemon que j'appelle create sur laquelle retourne un RoadUserContainer en fonction de RoadUserCreator ajouté. Une version simplifiée:

public class RoadUserCreationDaemon { 

    private SimulationManager simulationManager; 
    private List<RoadUserCreator> roadUserCreators; 

    public RoadUserCreationDaemon(SimulationManager simulationManager) { 
     this.simulationManager = simulationManager; 
     roadUserCreators = new ArrayList<RoadUserCreator>(); 
    } 

    public void addRoadUserCreator(RoadUserCreator roadUserCreator) { 
     roadUserCreators.add(roadUserCreator); 
    } 

    public RoadUserContainer createRoadUsers() { 
     RoadUserContainer roadUsers = new RoadUserContainerImpl(); 
     for (RoadUserCreator creator : roadUserCreators) { 
      roadUsers.addAll(createRoadUsers(creator)); 
     } 
     return roadUsers; 
    } 

    public RoadUserContainer createRoadUsers(
      RoadUserCreator roadUserCreator) { 
     return roadUserCreator.create(); 
    } 
} 

J'ai commencé par écrire un test (junit4/JMock2.5.1) pour createRoadUsers qui retourne un RoadUserContainer avec un créateur fourni. Puis j'ai commencé à écrire un test pour un createRoadUsers non-paramétrées pour voir si elle retourne un récipient avec tous les éléments des conteneurs individuels retournés par les créateurs:

@RunWith(JMock.class) 
public class TestRoadUserCreationDaemon { 
    Mockery context = new JUnit4Mockery();  
    private RoadUserCreationDaemon daemon;  
    private RoadUserCreator roadUserCreator;  
    private SimulationManager simulationManager;   
    private RoadUserContainer createdRoadUsers; 

    @Before 
    public void setUp() { 
     simulationManager = context.mock(SimulationManager.class); 
     daemon = new RoadUserCreationDaemon(simulationManager); 

     roadUserCreator = context.mock(RoadUserCreator.class); 
     createdRoadUsers = context.mock(RoadUserContainer.class); 
    }  

    @Test 
    public void createsRoadUsersAccordingToAllAddedCreators() throws Exception { 
     final RoadUserCreator anotherRoadUserCreator = context.mock(RoadUserCreator.class, "anotherRUC"); 
     final RoadUserContainer moreCreatedRoadUsers = context.mock(RoadUserContainer.class, "moreCRU"); 
     context.checking(new Expectations() {{ 
      oneOf (roadUserCreator).create(); will(returnValue(createdRoadUsers)); 
      oneOf (anotherRoadUserCreator).create(); will(returnValue(moreCreatedRoadUsers)); 

      oneOf (createdRoadUsers).roadUsersAsList(); 
      oneOf (moreCreatedRoadUsers).roadUsersAsList(); 
     }}); 

     daemon.addRoadUserCreator(roadUserCreator); 
     daemon.addRoadUserCreator(anotherRoadUserCreator); 
     daemon.createRoadUsers(); 

     //how to easily check that the two lists are equivilant - have same items, but not the same object? 
     //assertEquals(createdRoadUsers, daemon.createRoadUsers()); 
    } 

    @Test 
    public void createsRoadUsersAccordingToCreator() throws Exception { 

     context.checking(new Expectations() {{ 
      oneOf (roadUserCreator).create(); will(returnValue(createdRoadUsers)); 
     }}); 
     assertEquals(createdRoadUsers, daemon.createRoadUsers(roadUserCreator)); 
    } 
} 

Comme le commentaire dit ... Je ne suis pas sûr comment procéder d'une manière non-laide.

L'interface « RoadUserContainer »:

public interface RoadUserContainer extends Iterable<RoadUser> { 
    public void add(RoadUser roadUser); 
    public Iterator<RoadUser> iterator(); 
    public void addAll(RoadUserContainer createRoadUsers); 
    public List<RoadUser> roadUsersAsList(); 
    public boolean equals(RoadUserContainer otherContainer); 
    ... 
} 

Je suis nouveau à TDD et moqueur, ce qui est mon premier projet Java> 6 ans, alors ne hésitez pas à commenter l'esthétique accessoires!

Répondre

2

J'utiliserais probablement initialement de vrais conteneurs et simulerais les autres objets. Ensuite, utilisez hamcrest pour interroger l'objet résultant.

Le test que je voudrais créer ressemblerait à quelque chose comme ceci:

final RoadUser roadUser0 = context.mock(RoadUser.class, "roadUser0"); 
final RoadUser roadUser1 = context.mock(RoadUser.class, "roadUser1"); 
final RoadUser roadUser2 = context.mock(RoadUser.class, "roadUser2"); 

final RoadUserCreator roadUserCreator0 = context.mock(RoadUserCreator.class, "roadUserCreator0"); 
final RoadUserCreator roadUserCreator1 = context.mock(RoadUserCreator.class, "roadUserCreator1"); 

final RoadUserCreationDaemon daemon = new RoadUserCreationDaemon(null); 
daemon.addRoadUserCreator(roadUserCreator0); 
daemon.addRoadUserCreator(roadUserCreator1);   

context.checking(new Expectations() {{ 
    oneOf(roadUserCreator0).create(); will(returnValue(roadUsers(roadUser0, roadUser1))); 
    oneOf(roadUserCreator1).create(); will(returnValue(roadUsers(roadUser2))); 
}}); 

assertThat(daemon.createRoadUsers(), contains(roadUser0, roadUser1, roadUser2)); 

vous aurez besoin de ces importations en provenance hamcrest:

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.contains; 

Si l'ordre n'a pas d'importance, vous pouvez utiliser containsInAnyOrder au lieu de contient

vous devez également créer la méthode utilitaire "roadUsers"

public static RoadUserContainer roadUsers(final RoadUser... roadUsers) 
{ 
    return new RoadUserContainerImpl(roadUsers); 
} 

Une conception alternative serait de changer l'interface du RoadUserCreationDaemon

public void createRoadUsers(final RoadUserContainer roadUsers) { 
    for (final RoadUserCreator roadUserCreator : roadUserCreators) { 
     roadUsers.addAll(roadUserCreator.create()); 
    } 
} 

Ensuite, vous pouvez écrire des tests comme celui-ci:

final RoadUserContainer roadUserContainer0 = context.mock(RoadUserContainer.class, "roadUserContainer0"); 
final RoadUserContainer roadUserContainer1 = context.mock(RoadUserContainer.class, "roadUserContainer1"); 

final RoadUserContainer resultRoadUserContainer = context.mock(RoadUserContainer.class, "resultRoadUserContainer"); 

final RoadUserCreator roadUserCreator0 = context.mock(RoadUserCreator.class, "roadUserCreator0"); 
final RoadUserCreator roadUserCreator1 = context.mock(RoadUserCreator.class, "roadUserCreator1"); 

final RoadUserCreationDaemon daemon = new RoadUserCreationDaemon(null); 
daemon.addRoadUserCreator(roadUserCreator0); 
daemon.addRoadUserCreator(roadUserCreator1); 

context.checking(new Expectations() { 
    { 
     oneOf(roadUserCreator0).create(); 
     will(returnValue(roadUserContainer0)); 
     oneOf(roadUserCreator1).create(); 
     will(returnValue(roadUserContainer1)); 

     oneOf(resultRoadUserContainer).addAll(roadUserContainer0); 
     oneOf(resultRoadUserContainer).addAll(roadUserContainer1); 
    } 
}); 

daemon.createRoadUsers(resultRoadUserContainer); 

Si l'ordre des appels à "addAll" est important, vous pouvez utiliser un jmock sequence

1

Je pense que je me moquerais du Créateur mais je lui ferais retourner de vrais Conteneurs. L'idée du test est de s'assurer que le démon a invoqué toutes les méthodes de création du créateur, n'est-ce pas? Donc, votre condition de test ressemblerait à

RoadUserContainer result = daemon.createRoadUsers(); 

    // Check that the result contains both creator's users 
    Assert.assertEquals(createdRoadUsers.size() + moreCreatedRoadUsers.size(), result.size()); 

    for (RoadUser user : createdRoadUsers) 
     Assert.assertTrue(result.contains(user)); 
    for (RoadUser user : moreCreatedRoadUsers) 
     Assert.assertTrue(result.contains(user)); 
+0

OK, ainsi vos critères Est-il correct de créer un conteneur réel si le conteneur reste un objet 'value'? – neuronotic

+0

Il ne doit pas nécessairement s'agir d'un objet valeur. Vérifiez simplement que le conteneur créé par le démon contient tous les utilisateurs créés par les deux objets créateur. Cela a-t-il du sens? – jeff

+0

ouais, je pense que j'ai compris - et c'est actuellement comment j'ai procédé (merci;)). Cependant, il semble toujours laisser un peu d'odeur pour le coupler aux implémentations réelles d'autres objets. J'ai voté la réponse, mais je ne vais pas la marquer pour un jour ou trois. – neuronotic

Questions connexes