web-dev-qa-db-ja.com

Mockito-モックのリストを挿入する

私は次のコードを持っています:

@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クラスにはセッターがありません。できればそのままにしておきたいと思います。

16
fascynacja

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);
}
2
thopaw

@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);
}
11
Erwin Dupont

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

私にとっては、テストにのみ関連するヘルパーメソッドをコードに追加する必要がないため、これははるかにエレガントです。

1
Naruto Sempai

コレクションをあざけってはいけません。

必要なモックを作成してリストに入れます。

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

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);
  }
}
1
Andrew Spencer