我正在尝试为使用Provider框架的屏幕构建一个Widget测试。
该应用程序有一个屏幕和一个按钮,当我点击按钮时,它将触发一个功能来更新状态。一旦状态更新,将出现一个键为Key('LoadedString')
的字符串。
当在模拟器中手动测试时,这是预期的。
当我尝试使用小部件测试来验证预期行为时,似乎UI没有更新。
这是小部件:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'provider_page_state_controller.dart';
class ProviderPageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(providers: [
ChangeNotifierProvider<ProviderPageStateController>(
create: (context) => ProviderPageStateController())
], child: HomePage());
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var screenHeight = MediaQuery.of(context).size.height;
ScreenState state =
Provider.of<ProviderPageStateController>(context).pageState;
// Loading state
if (state == ScreenState.Loading) {
return Scaffold(
body: Container(
color: Colors.purple,
child: Center(child: Text('Loading...')),
));
}
// SuccessfullyLoaded state
if (state == ScreenState.SuccessfullyLoaded) {
return Scaffold(
body: Container(
color: Colors.green,
child: Center(
child: Column(
children: [
Padding(
padding:
EdgeInsets.fromLTRB(0, (screenHeight / 2) - 100, 0, 0),
),
Text('Loaded!', key: Key('LoadedString')),
Container(
margin: EdgeInsets.all(25),
color: Colors.blueAccent,
child: TextButton(
child: Text(
'Reset',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {
Provider.of<ProviderPageStateController>(context,
listen: false)
.updateState(ScreenState.InitialState);
},
),
),
],
))));
}
// InitialState (=default state)
return Scaffold(
body: Container(
color: Colors.white,
child: Center(
child: Column(
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, (screenHeight / 2) - 100, 0, 0),
),
Container(
key: Key('ButtonA'),
margin: EdgeInsets.all(25),
color: Colors.blueAccent,
child: TextButton(
child: Text(
'Button A',
style: TextStyle(color: Colors.white, fontSize: 20.0),
),
onPressed: () {
Provider.of<ProviderPageStateController>(context,
listen: false)
.functionA();
},
),
),
],
),
),
));
}
}
这是控制器:
import 'package:flutter/material.dart';
enum ScreenState { InitialState, Loading, SuccessfullyLoaded }
class ProviderPageStateController extends ChangeNotifier {
var pageState = ScreenState.InitialState;
void updateState(ScreenState screenState) {
pageState = screenState;
notifyListeners();
}
Future<void> functionA() async {
updateState(ScreenState.Loading);
Future.delayed(Duration(milliseconds: 1000), () {
updateState(ScreenState.SuccessfullyLoaded);
});
}
Future<void> reset() async {
updateState(ScreenState.InitialState);
}
}
这是Widget测试:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import '../provider_page/provider_page_state_controller.dart';
import '../provider_page/provider_page_widget.dart';
void main() {
testWidgets('ProviderPageWidget SuccessfullyLoaded test',
(WidgetTester tester) async {
final providerPageStateController = ProviderPageStateController();
await tester.pumpWidget(
ListenableProvider<ProviderPageStateController>.value(
value: providerPageStateController,
child: MaterialApp(
home: ProviderPageWidget(),
),
),
);
await providerPageStateController.functionA();
expect(providerPageStateController.pageState, ScreenState.Loading);
await tester.pumpAndSettle(Duration(seconds: 2));
expect(
providerPageStateController.pageState, ScreenState.SuccessfullyLoaded);
// Why does this assert fail?
expect(find.byKey(Key('LoadedString')), findsOneWidget);
});
}
为什么我的Widget测试的最后一个expect
失败了?
使用Provider.value
构造函数,因为您使用的是变量而不是实例化对象。为了确保所有依赖项都及时更新,在测试中使用lazy: false
标志,即使该值未被访问。结果更改如下:
void main() {
final providerPageState = ProviderPageState();
...
Provider<ProviderPageState>.value(
value: providerPageState,
child: MaterialApp(
home: ProviderPageWidget(),
),
lazy: false,
),
);
当使用提供者存储状态时,我还建议切换到ChangeNotifierProvider
。确保您的ProviderPageState
扩展了ChangeNotifier
并实现了所需的方法,作为参考,您可以使用ValueNotifier
的实现。
我发现了问题所在。我没有在widget测试中使用正确的widget。
将小部件测试更新为以下内容解决了问题:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import '../provider_page/provider_page_state_controller.dart';
import '../provider_page/provider_page_widget.dart';
void main() {
testWidgets('ProviderPageWidget SuccessfullyLoaded test',
(WidgetTester tester) async {
final providerPageStateController = ProviderPageStateController();
await tester.pumpWidget(
ListenableProvider<ProviderPageStateController>.value(
value: providerPageStateController,
child: MaterialApp(
home: HomePage(),
),
),
);
await providerPageStateController.functionA();
expect(providerPageStateController.pageState, ScreenState.Loading);
await tester.pumpAndSettle(Duration(seconds: 2));
expect(providerPageStateController.pageState, ScreenState.SuccessfullyLoaded);
// Why does this assert fail?
expect(find.byKey(Key('LoadedString')), findsOneWidget);
});
}
改变就行了:
:主页()