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