私は次のコードを持っています:
@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{...}
Mockitoを使用してテストを作成したいと思います。テストは次のように記述しました。
@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);
}
私はNullPointerExceptionをオンラインで取得しています:
filter(strategy -> strategy.isApplicable(id))
「strategies」リストは初期化されているが空であることを示しています。 MohitoがSpringと同じWashyで動作する方法はありますか?インターフェース「戦略」を実装するすべてのインスタンスをリストに自動的に追加しますか?
ところで、Wrapperクラスにはセッターがありません。できればそのままにしておきたいと思います。
Mockitoは、あなたがリストに何かを入れたいかどうかを知ることができませんstrategies。
これを再考して、このようなことをする必要があります
@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);
}
@Mockの代わりに@Spyで注釈を付けます。 Mockitoはインターフェイスをスパイできないため、ArrayListなどの具体的な実装を使用します。テストのセットアップ中に、モックをリストスパイに追加します。この方法では、テスト目的でのみテスト対象を変更する必要はありません。
@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);
}
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));
}
私にとっては、テストにのみ関連するヘルパーメソッドをコードに追加する必要がないため、これははるかにエレガントです。
コレクションをあざけってはいけません。
必要なモックを作成してリストに入れます。
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);
}
Erwin Dupontのソリューションは素晴らしいですが、テスト対象のオブジェクトのコンストラクターにモックのリストを挿入する必要がある場合は機能しません。
これが私がそれを回避した方法です。リストの1項目のソリューションを示しましたが、switch(index)
をget()
メソッドに入れることで、N項目に拡張できます。
class Wrapper {
private final List<Strategy> strategies;
Wrapper(List<Strategy> strategies) { this.strategies = new ArrayList<>(strategies); }
// ...
}
class WrapperTest {
@InjectMocks
private Wrapper testedObject;
@Spy
private List<Strategy> mockedStrategies new AbstractList<Strategy>() {
@Override public Trigger get(int index) { return trigger; } // can get away without bounds-checking
@Override public int size() { return 1; }
};
@Mock
private Strategy strategy;
@Test
public void testSomething() {
assertThat(testedObject).isNotNull();
assertThat(testedObject.getStrategies()).hasSize(1);
}
}