我有一个StatefulWidget(称之为MyWidget
),其状态(MyWidgetState
)有一个字段myData
,在initState()
期间初始化如下:
void initState() {
super.initState();
myData = new myData(config.someField.getId());
}
当用户按下按钮时,会在全局列表中添加或删除myData。
我尝试编写单元测试来测试此行为,但我不知道如何访问MyWidgetState。我尝试在setup()中包含这个:
widget = MyWidget();
widgetState = widget.createState();
widgetState.init();
但每次尝试initState()时都会崩溃,抱怨" someField在null"上被调用。没关系。我可能通过尝试这样做而作弊,我应该使用WidgetBuilder做一些事情或使用MyWidget启动应用程序,然后在正确实例化后在树中找到MyWidget。
如果我做了所有这些,一旦我这样做,我怎样才能访问MyWidget的MyWidgetState以获取myData的副本并将其与全局列表进行比较?
答案 0 :(得分:3)
使用tester.pumpWidgets
创建窗口小部件,然后使用tester.state(find.foo)
查找State
(其中find.foo
是查找窗口小部件的查找程序)。有关更多选项,请参阅WidgetTester
文档。
答案 1 :(得分:3)
如果您想对小部件状态的其中一种方法编写单元测试,可以通过以下方式完成:
// Assuming your stateful widget is like this:
class MyWidget extends StatefulWidget {
const MyWidget({this.someParam, Key? key}) : super(key: key);
final String someParam;
@override
MyWidgetState createState() => MyWidgetState();
}
@visibleForTesting
class MyWidgetState extends State<MyWidget> {
int methodToBeTested() {
// dummy implementation that uses widget.XXX
if (widget.someParam.isEmpty) return 0;
return 1;
}
@override
Widget build(BuildContext context) {
// return ...
}
}
// In your test file
void main() {
test('if widget.someParam is empty, do something', () {
const widget = MyWidget(someParam: '');
final element = widget.createElement(); // this will set state.widget
final state = element.state as MyWidgetState;
expect(state.methodToBeTested(), 0);
});
}
答案 2 :(得分:1)
您可以创建一个状态,然后访问它的内容。 遵循Ian Hickson的答案。以下是实现示例:
final MyWidgetState myWidgetState = tester.state(find.byType(MyWidget));
然后您可以访问状态内容:
myWidgetState.myData;
您可以在Flutter的repo中找到更多示例。
答案 3 :(得分:1)
如果您使用任何代码片段在 Flutter 中创建有状态的小部件,您可能已经注意到 Flutter 创建的状态类是一个私有类,它在开头由下划线构成。这很好,因为此类类不应在库外使用 - 除了测试。
在小部件/集成测试中,您可能希望访问状态类的变量。在这种情况下,将状态类标记为私有意味着您不能直接访问这些变量。这可能是不希望的。为了两全其美,我们可以使用 @visibleForTesting
装饰器。
下面给出了一个例子。
import 'dart:math';
import 'package:flutter/material.dart';
class CounterWidget extends StatefulWidget {
const CounterWidget({Key key}) : super(key: key);
@override
CounterWidgetState createState() => CounterWidgetState();
}
@visibleForTesting
class CounterWidgetState extends State<CounterWidget> {
int counter;
@override
void initState() {
super.initState();
var rndGen = Random(79);
counter = rndGen.nextInt(96);
}
@override
Widget build(BuildContext context) {
return Container(
child: ElevatedButton(
key: Key('incrementButton'),
onPressed: () {
setState(() {
counter++;
});
},
child: Text(
'Increment($counter)',
)));
}
}
@visibleForTesting
的文档说
用于注释公开的声明,以便它 比其他必要的更明显,使代码可测试。
分析器等工具可以提供反馈
注释与不在 lib 文件夹中的声明相关联 包、私有声明或未命名的声明 静态扩展,或声明在其外部引用 定义库或位于测试文件夹中的库 定义包。
这里的关键是,如果您在库或测试之外使用公共状态类,Dart 分析器会警告您,这在 Flutter 设计中很少是必需的。
使用 visibleForTesting
的想法来自于 here