【问题标题】:Testing GestureDetector on Image widget在图像小部件上测试 GestureDetector
【发布时间】:2019-06-13 20:41:33
【问题描述】:

我制作了一个简单的测试用例应用程序,您可以在其中单击使用 GestureDetector 的小部件,这会触发使用 setStatetapCount 变量的更新。

应用程序在模拟器中运行,文本如上所示正确更新,但一旦我尝试 Flutter 小部件测试,小部件测试就会失败,因为文本在测试环境中没有正确更新。

可重现的例子:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp();

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int tapCount = 0;

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Column(
            children: <Widget>[
              MyImage(
                onTap: () {
                  setState(() {
                    tapCount += 1;
                  });
                },
                imagePath: 'assets/my-image.jpg',
              ),
              Text(tapCount.toString())
            ],
          ),
        ),
      ),
    );
  }
}

class MyImage extends StatelessWidget {
  final Function() onTap;
  final String imagePath;

  const MyImage({
    Key key,
    @required this.onTap,
    @required this.imagePath,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        this.onTap();
      },
      child: Image.asset(
        imagePath,
        height: 100.0,
      ),
    );
  }
}

在 pubspec 中,我下载了一张随机图片,并验证该图片在模拟器中成功显示。

  assets:
    - assets/my-image.jpg

我的测试和样例一样,加了await tester.pumpAndSettle();,点击图片:

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    // Build our app and trigger a frame.
    await tester.pumpWidget(MyApp());
    await tester.pumpAndSettle();

    // Verify that our counter starts at 0.
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);

    // Tap the image and trigger a frame.
    await tester.tap(find.byType(MyImage));
    await tester.pump();
    await tester.pumpAndSettle();

    // Verify that our counter has incremented.
    expect(find.text('0'), findsNothing); // this test fails
    expect(find.text('1'), findsOneWidget); // this test fails
  });
}

当我运行测试时出现此错误

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
  Expected: no matching nodes in the widget tree
  Actual: ?:<exactly one widget with text "0" (ignoring offstage widgets): Text("0")>
   Which: means one was found but none were expected

When the exception was thrown, this was the stack:
#4      main.<anonymous closure> (file:///Projects/untitled/test/widget_test.dart:27:5)
<asynchronous suspension>
#5      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:82:23)
#6      TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:566:19)
<asynchronous suspension>
#9      TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:550:14)
#10     AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:893:24)
#16     AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:890:15)
#17     testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:81:22)
#18     Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:168:27)
<asynchronous suspension>
#19     Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:249:15)
<asynchronous suspension>
#24     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:246:5)
#25     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:166:33)
#30     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:165:13)
<asynchronous suspension>
#31     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:399:25)
<asynchronous suspension>
#45     _Timer._runTimers (dart:isolate/runtime/libtimer_impl.dart:382:19)
#46     _Timer._handleMessage (dart:isolate/runtime/libtimer_impl.dart:416:5)
#47     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
(elided 28 frames from class _FakeAsync, package dart:async, and package stack_trace)

This was caught by the test expectation on the following line:
  file:///Projects/untitled/test/widget_test.dart line 27

The test description was:
Counter increments smoke test
════════════════════════════════════════════════════════════════════════════════════════════════════

Test failed. See exception logs above.
The test description was: Counter increments smoke test

如果我尝试相同的测试,但将 MyImage 内的 Image 替换为 main.dart 内的另一个小部件(例如另一个 Text 小部件),则测试通过:

class MyImage extends StatelessWidget {
  final Function() onTap;
  final String imagePath;

  const MyImage({
    Key key,
    @required this.onTap,
    @required this.imagePath,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        this.onTap();
      },
      child: Text( // replaced Image with Text and test passes!
        imagePath,
      ),
    );
  }
}

这让我觉得问题是由于使用了图片,但我不知道为什么。

如果您想尝试测试,代码也上传到GitHub

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    以下是我对为什么它不适用于图像的看法。颤振测试在 FakeAsync 区域中运行,当您需要运行真正的异步代码(例如通过assetBundle 加载资产)时,资产不会被加载并且图像小部件的大小保持为零,因此命中测试失败。如果您事先设置图像的高度和宽度,则测试通过。

    【讨论】:

      猜你喜欢
      • 2019-04-13
      • 1970-01-01
      • 2021-09-22
      • 2021-04-24
      • 1970-01-01
      • 2021-03-25
      • 2017-01-27
      • 2021-05-09
      • 2019-02-25
      相关资源
      最近更新 更多