简体   繁体   English

Dart/Flutter 小部件:获取使用 kIsWeb 的路径的测试覆盖率

[英]Dart/Flutter Widget : Get Test Coverage for path that uses kIsWeb

I want to test and cover both paths of a widget that uses kIsWeb.我想测试并涵盖使用 kIsWeb 的小部件的两个路径。 the class looks like this :类看起来像这样:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (kIsWeb) {
      return Text("I'm web");
    } else {
      return Text("I'm not web");
    }
  }
}

After searching a while I found a way to test this here : Testing kIsWeb constant in flutter搜索了一段时间后,我在这里找到了一种测试方法: Testing kIsWeb constant in flutter

This is the Test class that I wrote :这是我写的测试类:

 class MockAppService extends Mock implements AppService {}
    
         void main() {
          final mockAppService = MockAppService();
          when(mockAppService.getkIsWeb())
              .thenAnswer((realInvocation) => true);
        
          testWidgets("add item", (WidgetTester tester) async {
            await tester.pumpWidget(MaterialApp(
              title: 'Flutter Demo',
              home: Scaffold(
                appBar: AppBar(
                  title: Text("title"),
                ),
                body: Center(
                  child: Text("message"),
                ),
              ),
            ));
            final PaymentPageState myWidgetState = tester.state(find.byType(PaymentPage));
            expect(find.byType(PaymentPage), findsOneWidget);
          });
        }

but I get the error但我得到了错误

type 'Null' is not a subtype of type 'bool' “Null”类型不是“bool”类型的子类型

My AppService class and the abstract class looks like this,我的 AppService 类和抽象类看起来像这样,

abstract class IAppService {
  bool getkIsWeb();
}

class AppService implements IAppService {
  bool getkIsWeb() {
    return kIsWeb;
  }
}

I'm new to Flutter and does not know a lot of things.我是 Flutter 新手,很多东西都不知道。 please help.请帮忙。

The solution you found about how to test kIsWeb should work, but you have to understand the whole picture.您找到的有关如何测试kIsWeb的解决方案应该可以工作,但您必须了解整个情况。

First of all, the main idea behind this approach is, to move the responsibility to decide, whether the application runs on the web or not, out of the widget and not use kIsWeb directly in the widget's build method.首先,这种方法背后的主要思想是,将决定应用程序是否在 Web 上运行的责任移出小部件,而不是直接在小部件的构建方法中使用kIsWeb

Therefore an interface named IAppService is introduced and the class AppService implements this interface.因此引入了一个名为IAppService的接口, AppService类实现了这个接口。 The interface is not really needed and I will work with the AppService class directly in my example.该接口并不是真正需要的,我将在我的示例中直接使用AppService类。

Your widget should use an instance of AppService and call getKIsWeb on it, instead of using the kIsWeb constant directly.您的小部件应使用AppService实例并在其上调用getKIsWeb ,而不是直接使用kIsWeb常量。 There are many ways to provide the instance to the widget.有许多方法可以将实例提供给小部件。 Using a constructor parameter is one of the easiest, but you may want to take a look at dependency injection or state management solutions in the future.使用构造函数参数是最简单的方法之一,但您将来可能想看看依赖注入或状态管理解决方案。

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key, required this.appService}) : super(key: key);

  final AppService appService;

  @override
  Widget build(BuildContext context) {
    if (appService.getKIsWeb()) {
      return const Text('I\'m web');
    } else {
      return const Text('I\'m not web');
    }
  }
}

class AppService {
  bool getKIsWeb() {
    return kIsWeb;
  }
}

And last not least.最后并非最不重要。 When you test your widget, you give it a mocked implementation of the AppService class, which returns either true or false when getKIsWeb gets called, depending on what you want to test.当你测试你的小部件时,你给它一个AppService类的模拟实现,它在调用getKIsWeb时返回 true 或 false,这取决于你想要测试的内容。

class MockAppService extends Mock implements AppService {}

void main() {
  testWidgets('Test web widget', (WidgetTester tester) async {
    final mockAppService = MockAppService();
    when(() => mockAppService.getKIsWeb()).thenReturn(true);

    await tester.pumpWidget(
      MaterialApp(
        title: 'Flutter Demo',
        home: Scaffold(
          body: MyWidget(
            appService: mockAppService,
          ),
        ),
      ),
    );

    final webTextFinder = find.text('I\'m web');
    expect(webTextFinder, findsOneWidget);
  });

  testWidgets('Test not web widget', (WidgetTester tester) async {
    final mockAppService = MockAppService();
    when(() => mockAppService.getKIsWeb()).thenReturn(false);

    await tester.pumpWidget(
      MaterialApp(
        title: 'Flutter Demo',
        home: Scaffold(
          body: MyWidget(
            appService: mockAppService,
          ),
        ),
      ),
    );

    final webTextFinder = find.text('I\'m not web');
    expect(webTextFinder, findsOneWidget);
  });
}

Please note that I am using Mocktail here instead of Mockito.请注意,我在这里使用的是 Mocktail 而不是 Mockito。 But you should get the idea.但你应该明白这一点。

when(() => mockAppService.getKIsWeb()).thenReturn(false); is Mocktails way to define the mocked behavior.是定义模拟行为的 Mocktails 方式。 https://pub.dev/packages/mocktail https://pub.dev/packages/mocktail

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM