web-dev-qa-db-fra.com

Mockito - Injecter une liste de faux

J'ai le code suivant:

@Component 
public class Wrapper
{ 
    @Resource 
    private List<Strategy> strategies;

    public String getName(String id)
    {
    // the revelant part of this statement is that I would like to iterate over "strategies"
        return strategies.stream()
            .filter(strategy -> strategy.isApplicable(id))
            .findFirst().get().getAmount(id);
    } 
}

@Component 
public class StrategyA implements Strategy{...}

@Component 
public class StrategyB implements Strategy{...}

Je voudrais créer un test pour cela en utilisant Mockito. J'ai écrit le test comme suit:

@InjectMocks
private Wrapper testedObject = new Wrapper ();

// I was hoping that this list will contain both strategies: strategyA and strategyB
@Mock
private List<Strategy> strategies;

@Mock
StrategyA strategyA;

@Mock
StrategyB strategyB;

@Test
public void shouldReturnNameForGivenId()
{   // irrevelant code...
    //when
    testedObject.getName(ID);
}

Je reçois NullPointerException en ligne:

filter(strategy -> strategy.isApplicable(id))

, qui indique que la liste "strategies" est initialisée mais vide. Y a-t-il un moyen pour Mohito de se comporter de la même manière que le printemps? Ajouter automatiquement toutes les instances implémentant l'interface "Strategy" à la liste?

Btw, je n'ai pas de setters en classe Wrapper et j'aimerais le laisser de cette manière si possible.

7
fascynacja

Mockito ne peut pas savoir que vous voulez mettre quelque chose dans la liste stratégies .

Vous devriez repenser cela et faire quelque chose comme ça

@InjectMocks
private Wrapper testedObject = new Wrapper ();

private List<Strategy> mockedStrategies;

@Mock
StrategyA strategyA;

@Mock
StrategyB strategyB;

@Before
public void setup() throws Exception {
    mockedStrategies = Arrays.asList(strategyA, strategyB);
    wrapper.setStrategies(mockedStrategies);
}
0
thopaw

Annotez-le avec @Spy au lieu de @Mock. Comme Mockito ne peut pas espionner une interface, utilisez une implémentation concrète, par exemple ArrayList. Pendant la configuration du test, ajoutez les simulacres à l'espion List. De cette façon, vous n'avez pas besoin de modifier votre sujet de test uniquement à des fins de test.

@InjectMocks
private Wrapper testedObject = new Wrapper();

@Spy
private ArrayList<Strategy> mockedStrategies;

@Mock
private StrategyA strategyA;

@Mock
private StrategyB strategyB;

@Before
public void setup() throws Exception {
    mockedStrategies.add(strategyA);
    mockedStrategies.add(strategyB);
}
8
Erwin Dupont

Vous ne devriez pas vous moquer des collections.

Créez les simulacres dont vous avez besoin et mettez-les dans une liste:

private List<Strategy> strategies; // not mocked!

@Mock
StrategyA strategyA;

@Mock
StrategyB strategyB;

@Before
public void setup(){
  strategies= Arrays.asList(strategyA,strategyB);
  testedObject.strategies= strategies;
}

@Test
public void shouldReturnNameForGivenId()
{   // irrevelant code...
    //when
    testedObject.getName(ID);
}
1
Timothy Truckle

Pourquoi ne pas simuler votre appel à toStream()?

@InjectMocks
private Wrapper testedObject = new Wrapper();

private List<Strategy> mockedStrategies;

@Mock
StrategyA strategyA;

@Mock
StrategyB strategyB;

@Before
public void setup() {
    when(strategies.stream()).thenReturn(Stream.of(strategyA, strategyB));
}

Pour moi, cela est beaucoup plus élégant car cela ne vous oblige pas à ajouter une méthode d'assistance qui ne concerne que le test de votre code.

0
Naruto Sempai