简体   繁体   English

Dart / Flutter Web:如何编写涵盖 `kIsWeb == true` 的测试?

[英]Dart / Flutter Web: How to write a test that covers `kIsWeb == true`?

I want to run a unit test that covers both possible cases, web and non-web deployment.我想运行一个单元测试,涵盖可能的情况,Web 和非 Web 部署。 The code for the class to be tested basically 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");
    }
  }
}

kIsWeb is a constant provided by Dart that determines if the application was compiled to run on the web. kIsWeb是 Dart 提供的一个常量,用于确定应用程序是否编译为在 Web 上运行。

My current test class implementation is only able to test the non-web path.我当前的测试类实现只能测试非 web 路径。 Is there a way to create a test for the case of kIsWeb == true ?有没有办法为kIsWeb == true的情况创建测试?

Try to run test like this:尝试像这样运行测试:

flutter test --platform chrome颤振测试——平台铬

Unfortunately this method may not work on some platforms ( issue for Windows 10).不幸的是,此方法可能不适用于某些平台(Windows 10 的问题)。 Flutter for web is still in BETA. Flutter for web仍处于测试阶段。

More information is available here .更多信息可在此处获得。

I'm not sure if there is a way to test it directly from a StatelessWidget, but I can show you a way that makes use of some concepts of Clean Architecture.我不确定是否有办法直接从 StatelessWidget 测试它,但我可以向您展示一种利用清洁架构的一些概念的方法。 Basically, you want to decouple the UI (that is, your widgets) from pure logic.基本上,您希望将 UI(即您的小部件)与纯逻辑分离。 So, what I usually do is to have a class that handles the logic, like this:所以,我通常做的是有一个处理逻辑的类,如下所示:

class MyWidgetViewModel {
  /// Whether or not the current environment is web.
  /// Should only be overridden for testing purposes.
  /// Otherwise, defaults to [kIsWeb].
  @visibleForTesting
  bool isWeb = kIsWeb;
}

Here, I have wrapped the kIsWeb constant in another variable isWeb , which defaults to kIsWeb.在这里,我将kIsWeb常量包装在另一个变量isWeb中,该变量默认为 kIsWeb。 This means that it can be reassigned at a later time and, moreover, it is only visible to test cases thanks to the annotation @visibleForTesting .这意味着它可以在以后重新分配,而且,由于注释@visibleForTesting ,它只对测试用例可见。

At this point, we can reference that class in the widget.此时,我们可以在小部件中引用该类。 I generally use Dependency Injection with either Provider or BLoC, but here, for the sake of simplicity, I'll just pass the ViewModel in the widget constructor.我通常将依赖注入与 Provider 或 BLoC 一起使用,但在这里,为了简单起见,我将只在小部件构造函数中传递 ViewModel。

class MyWidget extends StatelessWidget {
  final MyWidgetViewModel myViewModel;

  const MyWidget(this.myViewModel, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (myViewModel.isWeb) { //<- Here we use `isWeb` instead of `kIsWeb`
      return Text("I'm web");
    } else {
      return Text("I'm not web");
    }
  }
}

Finally, we can exploit the isWeb variable in the tests.最后,我们可以在测试中利用isWeb变量。 Don't forget to pass an instance of MyWidgetViewModel() to your MyWidget during the setup of the variables.不要忘记在设置变量期间将MyWidgetViewModel()的实例传递给您的MyWidget

test(
  'Test based on platform (is web or not).',
  () async {
    // Arrange (setup)
    ...
    final MyWidgetViewModel myViewModel = MyWidgetViewModel();
    myViewModel.isWeb = true; //<- Use this to assign the value you prefer
    ...


    // Assert (expect, verify)
    ...
  },
);

You could also add a constructor and attribute to your widget which you would decorate with @visibleForTesting .您还可以将构造函数和属性添加到您将使用@visibleForTesting装饰的小部件。 Something similar to:类似于:

class MyWidget extends StatelessWidget {
  final bool isTestingForWeb;
  MyWidget({@visibleForTesting this.isTestingForWeb = false});

  @override
  Widget build(BuildContext context) {
    if (kIsWeb || isTestingForWeb) {
      return Text("I'm web");
    } else {
      return Text("I'm not web");
    }
  }
}

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

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