9

我有一个 StatefulWidget(调用它MyWidget),它的 State ( 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 was called on null”。没关系。我尝试这样做可能是在作弊,我应该使用 WidgetBuilder 做一些事情或使用 MyWidget 启动应用程序,然后在正确实例化后在树中找到 MyWidget。

如果我做了所有这些,一旦我这样做了,我如何访问该 MyWidget 的 MyWidgetState 以获取 myData 的副本并将其与全局列表进行比较?

4

4 回答 4

19

您可以创建一个状态,然后访问它的内容。按照伊恩·希克森的回答。下面是一个实现的例子:

final MyWidgetState myWidgetState = tester.state(find.byType(MyWidget));

然后你可以访问状态内容:

myWidgetState.myData;

您可以在 Flutter 的repo中找到更多示例。

于 2019-11-17T10:25:09.923 回答
7

使用 创建小部件tester.pumpWidgets,然后使用tester.state(find.foo)查找Statefind.foo查找小部件的查找器在哪里)。有关更多选项,请参阅WidgetTester文档。

于 2017-02-09T05:06:29.090 回答
6

如果您想对小部件状态的方法之一编写单元测试,可以这样做:

// 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);
  });
}
于 2021-07-20T13:14:20.513 回答
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 文件夹中的声明、私有声明或未命名静态扩展中的声明相关联,或者声明在其定义库或位于 test 文件夹中的库之外引用定义包。

这里的关键要点是,如果您在库或测试之外使用公共状态类,Dart 分析器会警告您,这在 Flutter 设计中很少需要。

使用的想法visibleForTesting来自这里

于 2021-07-03T21:13:03.940 回答