我正在尝试测试小部件的方法是否确实被调用,但我似乎无法正确执行。
我的小部件看起来像这样:
class MyWidget extends StatefulWidget {
const MyWidget({
Key? key,
required this.callSaveData,
}) : super(key: key);
final Function(DataModel dataModel) callSaveData;
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
DataModel dataModel;
...
@override
Widget build(BuildContext context) {
...
return ElevatedButton(
onPressed: () {
widget.callSaveData(someStateData);
},
child: Text('Hello'),
)
}
}
我的测试是这样的:
class MockCallSaveData extends Mock {
void call(DataModel mockDataModel);
}
void main() {
late Function(DataModel mockDataModel)
mockCallSaveData;
group('Tests', () {
setUp(() {
mockCallSaveData = MockCallSaveData();
});
Future<void> _buildScreen(WidgetTester tester) async {
return tester.pumpWidget(
...
return MyWidget(
callSaveData: mockCallSaveData,
);
);
}
testWidgets('Test widget', (WidgetTester tester) async {
when(() => mockCallSaveData(mockDataModel))
.thenAnswer((_) => null);
await _buildScreen(tester);
await tester.pumpAndSettle();
... interact with UI, tap the button that triggers the callback ...
verify(
() => mockCallSaveData(mockDataModel),
);
});
});
}
但我不断收到以下错误
The following TestFailure was thrown running a test:
No matching calls. All calls: MockCallSaveData.call(mockDataModel(null, test_city,
null, [email protected], test_firstName, test_last_name, H123, null, null, 1, 1135, +41 79 123 34 56,
test_street, test_username, 1234, null, null, null))
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
因此,看起来模拟已被调用,并且具有正确的数据。 “mockCallSaveData”实例应该是相同的,它在 setUp() 中实例化,传递给测试,同时在 testWidgets() 中引用。
任何帮助将不胜感激,我花了几个小时试图让它发挥作用。
修复了它,感谢@jamesdlin 的提示。 我没有注意到传递给
DataModel
的 widget.callSaveData(someStateData);
实例正在被操纵。
就在该调用之前,有一个实用程序方法执行如下操作:
void textChanged({
String? zip,
String? street,
... etc etc
}) {
userViewModel = DataModel(
zip: zip ?? dataModel!.zip,
street: street ?? dataModel!.street,
... etc
);
}
这当然导致了新实例的交付。 现在,我所做的就是解决这个问题,并使代码总体上更好一点,就是向我的
DataModel
类添加一个 copyWith 方法。
class DataModel extends Equatable {
DataModel({this.zip, this.street, ... etc});
String? zip;
String? city;
DataModel copyWith({String? zip, String? city}) {
return DataModel(
zip: zip ?? this.zip,
city: city ?? this.city,
);
}
}
这允许我按如下方式测试我的小部件:
testWidgets('Test widget', (WidgetTester tester) async {
const String test_zip = 'test_zip';
when(() => mockCallSaveData(mockDataModel))
.thenAnswer((_) => null);
await _buildScreen(tester);
await tester.pumpAndSettle();
... interact with UI, tap the button that triggers the callback ...
verify(
() => mockCallSaveData(mockDataModel.copyWith(zip: test_zip)),
);
});
现在一切正常。