はじめに
Flutterでユニットテストを行う際、Mockitoを使用してモックオブジェクトを作成することが一般的です。しかし、特定の状況下(今回はsealedクラスをモック化した)ではエラーが発生し、テストの実行が妨げられることがあります。本記事では、provideDummyとprovideDummyBuilderを使用してそのようなエラーを解決する方法を解説します。
エラーの発生するコード
以下のコードを実行するとエラーが発生します。
final target = MockCounterPresenter();
when(target.counter).thenReturn('255');
final mockFormatter = MockThousandsSeparatedFormatter();
when(target.selectedFormatter).thenReturn(mockFormatter);
エラー内容
The following MissingDummyValueError object was thrown running a test:
MissingDummyValueError: NumberFormatter
This means Mockito was not smart enough to generate a dummy value of type
'NumberFormatter'. Please consider using either 'provideDummy' or 'provideDummyBuilder'
functions to give Mockito a proper dummy value.
Please note that due to implementation details Mockito sometimes needs users
to provide dummy values for some types, even if they plan to explicitly stub
all the called methods.
エラーの原因
エラーの原因は、NumberFormatterクラスがsealedであるため、Mockitoが自動的にダミーインスタンスを生成できないことにあります。
sealed class NumberFormatter {
String get name;
String format(int value);
}
sealedクラスは継承やインスタンス化に制限があるため、MockitoはNumberFormatter型のダミー値を生成できず、MissingDummyValueErrorが発生します。
また、NumberFormatter自体はモックかできなかったので、その継承クラスThousandsSeparatedFormatterをモック化しました。
解決方法
この問題を解決するために、MockitoはprovideDummyまたはprovideDummyBuilderを提供しています。これらの関数を使用して、Mockitoに手動でダミー値を提供することができます。
provideDummyの使用
provideDummy<T>(T dummy)を使用して、特定の型Tのダミーインスタンスを提供します。
final target = MockCounterPresenter();
when(target.counter).thenReturn('255');
final mockFormatter = MockThousandsSeparatedFormatter();
provideDummy<NumberFormatter>(mockFormatter);
これにより、NumberFormatter型が必要なときにmockFormatterが使用され、エラーが解消されます。
provideDummyBuilderの使用
provideDummyBuilder<T>(T Function(Object? parent, Invocation invocation) builder)を使用して、ダミーインスタンスを動的に生成する関数を提供します。
provideDummyBuilder<NumberFormatter>((parent, invocation) {
// 必要に応じてダミーインスタンスを生成
return MockThousandsSeparatedFormatter();
});
メソッドの挙動の確認
以下のテストコードで、provideDummyとprovideDummyBuilderの挙動を確認します。
group('test of mockito', () {
test('provideDummy', () {
final mockFormatter1 = MockThousandsSeparatedFormatter();
final mockFormatter2 = MockThousandsSeparatedFormatter();
final target = MockCounterPresenter();
provideDummy<NumberFormatter>(mockFormatter1);
expect(target.selectedFormatter, mockFormatter1);
expect(target.selectedFormatter, isNot(mockFormatter2));
provideDummy<NumberFormatter>(mockFormatter2);
expect(target.selectedFormatter, mockFormatter2);
expect(target.selectedFormatter, isNot(mockFormatter1));
});
test('provideDummyBuilder', () {
final mockFormatter1 = MockThousandsSeparatedFormatter();
final mockFormatter2 = MockThousandsSeparatedFormatter();
final target = MockCounterPresenter();
provideDummyBuilder<NumberFormatter>((parent, invocation) {
expect(parent, target);
print(invocation);
print(invocation.memberName); // Symbol("selectedFormatter")
print(invocation.isGetter); // true
return mockFormatter1;
});
expect(target.selectedFormatter, mockFormatter1);
expect(target.selectedFormatter, isNot(mockFormatter2));
provideDummyBuilder<NumberFormatter>(
(parent, invocation) => mockFormatter2);
expect(target.selectedFormatter, mockFormatter2);
expect(target.selectedFormatter, isNot(mockFormatter1));
});
});
テスト結果の解説
-
provideDummyの場合:
provideDummyに渡したインスタンスが、NumberFormatter型のダミー値として使用されます。- 再度
provideDummyを呼び出すと、ダミー値が新しいインスタンスに更新されます。
-
provideDummyBuilderの場合:
provideDummyBuilderに渡した関数が、NumberFormatter型が必要なときに呼び出され、ダミー値を動的に生成します。- ビルダー関数内で、
parentやinvocationを使用して、呼び出し元のコンテキストや状況に応じたダミー値を返すことができます。
まとめ
MissingDummyValueErrorは、Mockitoが特定の型のダミー値を自動生成できないときに発生します。これは主にsealedクラスや抽象クラスなどで起こります。この問題を解決するためには、provideDummyまたはprovideDummyBuilderを使用して、Mockitoにダミー値を提供する必要があります。
provideDummyは、特定のインスタンスをダミー値として提供します。provideDummyBuilderは、ダミー値を生成する関数を提供し、動的なダミー値の生成が可能です。
これらの機能を適切に活用することで、Mockitoでのテストがより円滑に進み、テストコードの柔軟性と信頼性が向上します。