【问题标题】:Why do some Flutter widget tests fail if executed together but pass individually?如果一起执行但单独通过,为什么一些 Flutter 小部件测试会失败?
【发布时间】:2021-10-30 00:35:26
【问题描述】:

当在同一个文件中有多个测试,并且一个接一个地运行一个测试时。某些类型的测试失败,但单独运行时相同的测试通过。

这是我目前的测试文件,虽然有点长:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:rec/Components/Inputs/text_fields/DniTextField.dart';
import 'package:rec/Helpers/Validators.dart';

import '../../test_utils.dart';

void main() {
  testWidgets('DniTextField works with invalid DNI', (WidgetTester tester) async {
    var key = GlobalKey<DniTextFieldState>();
    var formKey = GlobalKey<FormState>();
    var onChangedResult;

    var widget = Form(
      key: formKey,
      child: DniTextField(
        key: key,
        onChange: (String value) {
          onChangedResult = value;
        },
        validator: (s) => Validators.verifyIdentityDocument(s),
      ),
    );
    await tester.pumpWidget(
      TestUtils.wrapPublicRoute(widget),
    );
    await tester.pumpAndSettle();

    // Test that widget has at least rendered
    TestUtils.widgetExists(widget);

    // Enter text into field with
    var widgetFinder = find.byWidget(widget);
    await tester.tap(widgetFinder);
    await tester.showKeyboard(widgetFinder);
    await tester.enterText(widgetFinder, 'invaliddni');

    await tester.pumpAndSettle();

    expect(onChangedResult, 'invaliddni');

    expect(formKey.currentState.validate(), false);
  });

  testWidgets('DniTextField works with valid DNI', (WidgetTester tester) async {
    var key = GlobalKey<DniTextFieldState>();
    var formKey = GlobalKey<FormState>();
    var onChangedResult;

    var widget = Form(
      key: formKey,
      child: DniTextField(
        key: key,
        onChange: (String value) {
          onChangedResult = value;
        },
        validator: (s) => Validators.verifyIdentityDocument(s),
      ),
    );
    await tester.pumpWidget(
      TestUtils.wrapPublicRoute(widget),
    );
    await tester.pumpAndSettle();

    // Enter text into field
    var widgetFinder = find.byType(DniTextField);
    await tester.tap(widgetFinder);
    await tester.showKeyboard(widgetFinder);
    await tester.enterText(widgetFinder, '80008000k');

    await tester.pumpAndSettle();

    expect(onChangedResult, '80008000k');

    expect(formKey.currentState.validate(), true);
  });

  testWidgets('DniTextField works with valid DNI with trailing space', (WidgetTester tester) async {
    var key = GlobalKey<DniTextFieldState>();
    var formKey = GlobalKey<FormState>();
    var onChangedResult;

    var widget = Form(
      key: formKey,
      child: DniTextField(
        key: key,
        onChange: (String value) {
          onChangedResult = value;
        },
        validator: (s) => Validators.verifyIdentityDocument(s),
      ),
    );
    await tester.pumpWidget(TestUtils.wrapPublicRoute(widget));
    await tester.pumpAndSettle();

    // Enter text into field
    var widgetFinder = find.byWidget(widget);
    await tester.tap(widgetFinder);
    await tester.showKeyboard(widgetFinder);
    await tester.enterText(widgetFinder, '80008000k ');

    await tester.pumpAndSettle();

    // The value emitted by the field, should be free of trailing whitespace
    expect(onChangedResult, '80008000k');

    expect(formKey.currentState.validate(), true);
  });
}

如果我这样运行:

$ flutter test test/Components/inputs/dni_text_field_test.dart

第一个测试通过,但接下来的 2 个没有,吐出以下错误:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following assertion was thrown running a test:
The finder "zero widgets with the given widget
(DniTextField-[LabeledGlobalKey<DniTextFieldState>#0fb86]) (ignoring offstage widgets)" (used in a
call to "tap()") could not find any matching widgets.

When the exception was thrown, this was the stack:
#0      WidgetController._getElementPoint (package:flutter_test/src/controller.dart:902:7)
#1      WidgetController.getCenter (package:flutter_test/src/controller.dart:841:12)
#2      WidgetController.tap (package:flutter_test/src/controller.dart:273:18)
#3      main.<anonymous closure> (file:///[masked]/test/Components/inputs/dni_text_field_test.dart:99:18)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)

如果我随后注释掉第一个测试,那么第二个通过但第三个没有。正如我所说,如果我单独运行它们,则测试通过。

我找不到任何关于此的信息,甚至一件事都没有。也许这里有人可以指导我正确的方向。我对 Flutter 小部件测试有点陌生,所以我可能会遗漏一些重要的东西。

我现在找到的唯一解决方案是将每个测试放在一个单独的文件中。但这并不理想,将相关测试包含在同一个文件中会更好。 Flutter 的示例表明每个文件都允许进行多个测试。

Flutter 版本:2.4.0-5.0.pre.87

【问题讨论】:

  • 如果您的测试单独通过而不是一起通过,这表明您的测试不是密封的:也就是说,您在某处具有某种形式的状态,这些状态在测试中被保留。一个最小的、可重现的例子会有所帮助。
  • 哦,谢谢,有道理。虽然我唯一与状态相关的东西是flutter_localizations,但这会导致问题吗?我会尝试建立一个例子
  • 发现问题,它与本地化有关。有没有办法在每次测试之前重置状态?或者你会如何建议接近这个?再次感谢!
  • 我又一次大声笑'^^我在这个答案中找到了修复stackoverflow.com/a/52474073/5900163

标签: flutter dart flutter-test


【解决方案1】:

我想当不同的测试没有创建不同的小部件实例(或者它们以某种其他方式发生冲突)时,就会出现这个问题,但是有一个转机可能会对您有所帮助。

如果您想创建一个按钮来运行所有测试 - 您可以创建一个 bash(或 Windows 上的 cmd)文件,该文件按顺序运行所有测试。

例如all_tests.cmd

dart test_1.dart
dart test_2.dart
dart test_3.dart

这不是最清晰的解决方案,但它可能第一次起作用。

【讨论】:

  • 是的,这在某种程度上是我过去的解决方案,也许应该将它添加到问题中。我希望让我确切地知道这个问题,因为我希望将所有相关测试都放在一个文件中。我必须看到颤振在他们的示例中做到这一点,所以它可以做到......无论如何,谢谢!
【解决方案2】:

好的,我找到了解决方案和原因,感谢this 问题和this SO 问题。

主要问题是使用从 JSON 文件加载的本地化。解决方案是用 tester.runAsync() 包装每个测试

testWidgets('widget test 2', (WidgetTester tester) async {
  await tester.runAsync(() async {
    // tests
  });
});

【讨论】:

  • 谢谢你,这对我有用。我一直在这个问题上浪费时间。
猜你喜欢
  • 2012-02-17
  • 2021-08-18
  • 2015-07-15
  • 1970-01-01
  • 2021-08-27
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多