DartにはMockito というモック用のテストライブラリがあります。 Javaにも同じ名前のライブラリ があってDartの方はこのライブラリをインスパイアして作られているため、元々JavaでMockitoを使っていた方はすぐに使えるようになると思います。
DartのMockitoも使い方は大体同じなのですが、同じ引数のメソッドを複数回モックするときに困ったのでメモします。
例
Repositoryクラスをコンストラクタで渡して動くServiceクラスを用意します。
中身はシンプルに掛け算をして足しているだけです。
- ExampleRepository
class ExampleRepository {
int multiplication(int argument) {
return argument * 100;
}
}
- ExampleService
class ExampleService {
ExampleService(this.exampleRepository);
final ExampleRepository exampleRepository;
int calculate(int a, int b) {
return exampleRepository.multiplication(a) +
exampleRepository.multiplication(b);
}
}
Mockitoを使ったテスト
本家のJavaではthenReturn
の引数が複数回とれるようになっているので、1回目の呼び出しと2回目の呼び出しが異なる場合に順番どおりにmockできます。
- Java
@ExtendWith(MockitoExtension.class)
public class ExampleServiceTest {
@Mock
ExampleRepository mExampleRepository;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testSaveArgMatch() throws Exception {
final ExampleService exampleService = new ExampleService(mExampleRepository);
// 1回目:1000, 2回目:2000
Mockito.when(mExampleRepository.multiplication(10)).thenReturn(1000, 2000);
final int result = exampleService.calculate(10, 10);
assertEquals(3000, result);
}
}
この場合 mExampleRepository.multiplication(10)
の1回目の結果は1000になって、2回目の結果は2000にモックされます。
- Dart
JavaのようにDartでも thenReturn
を複数セットしたいのですが現状は書けません。
class MockExampleRepository extends Mock implements ExampleRepository {}
void main() {
final exampleRepository = MockExampleRepository();
final service = ExampleService(exampleRepository);
setUp(() {
reset(exampleRepository);
});
test('test', () async {
when(exampleRepository.multiplication(10)).thenReturn(1000, 2000); // syntax error
final result = service.calculate(10, 10);
expect(result, 3000);
});
}
Dartでも同じメソッドで異なる値を複数回モックするには、intのcall countのような変数を用意して配列でインクリメントします。
var callCount = 0;
when(mockedFoo.bar()).thenAnswer((_) => [1000, 2000][callCount++]);
ポイントはthenReturn
ではなくthenAnswer
を使うことです。
今回モックするメソッドはFuture
ではないので単純にモックするだけならthenReturn
でも問題ないのですが、このように複数回モックする場合はthenAnswer
で呼ぶ必要があります。
Dart版の完成形はこのようになります。
class MockExampleRepository extends Mock implements ExampleRepository {}
void main() {
final exampleRepository = MockExampleRepository();
final service = ExampleService(exampleRepository);
setUp(() {
reset(exampleRepository);
});
test('test', () async {
var callCount = 0;
when(exampleRepository.multiplication(10)).thenAnswer((_) => [1000, 2000][callCount++]);
final result = service.calculate(10, 10);
expect(result, 3000);
});
}
これでDartのMockitoでも複数回呼び出しで異なる値を返せるようになりました。
Mockitoのドキュメントにはなかったので(多分)メモでした。