单元测试介绍

我们如何保证 app 在增加了新特性或者改变了现有功能之后还能正常工作呢?答案是写测试!

How can you ensure that your app continues to work as you add more features or change existing functionality? By writing tests.

使用单元测试可轻松地验证单个函数、方法或类的行为。test 这个 package 提供了写单测的核心框架, flutter_test 包则提供了额外的功能来测试 widget。

Unit tests are handy for verifying the behavior of a single function, method, or class. The test package provides the core framework for writing unit tests, and the flutter_test package provides additional utilities for testing widgets.

本教程将会为大家演示 test package 的用法,内容如下:

This recipe demonstrates the core features provided by the test package using the following steps:

  1. test 或者 flutter_test加入依赖;

    Add the test or flutter_test dependency.

  2. 创建测试文件;

    Create a test file.

  3. 创建一个要测试的类;

    Create a class to test.

  4. 为创建的类写一个测试;

    Write a test for our class.

  5. 整合多个测试到一个 group

    Combine multiple tests in a group.

  6. 执行测试。

    Run the tests.

使用单元测试可轻松地验证单个函数、方法或类的行为。test 包提供了写单测的核心框架, flutter_test 包则提供了额外的功能来测试 Widget。

关于测试包的更多内容,可移步至 测试包文档.

For more information about the test package, see the test package documentation.

1. 添加测试依赖 —— 将 test 或者 flutter_test加入依赖文件

1. Add the test or flutter_test dependency

如果 Dart 包没有依赖 Flutter,可以导入 test 包。Test 包提供了编写测试所需要的核心功能。当我们写的包需要被 web、服务端和 Flutter app 使用时,这是最佳的方式。

If you’re working on a Dart package that does not depend on Flutter, you can import the test package. The test package provides the core functionality for writing tests in Dart. This is the best approach when writing packages consumed by web, server, and Flutter apps.

dev_dependencies:
  test: <latest_version>

2. 创建测试文件

2. Create a test file

本例中,我们会创建两个文件:counter.dartcouter_test.dart

In this example, create two files: counter.dart and counter_test.dart.

counter.dart 文件包含一个位于 lib 文件夹的待测试类,而位于 test 文件夹的counter_test.dart 文件将包含测试本身,。

The counter.dart file contains a class that you want to test and resides in the lib folder. The counter_test.dart file contains the tests themselves and lives inside the test folder.

通常测试文件应位于放置在 Flutter 应用或包的根目录下的 test 文件夹。

In general, test files should reside inside a test folder located at the root of your Flutter application or package.

创建完成后,文件目录结构如下:

When you’re finished, the folder structure should look like this:

counter_app/
  lib/
    counter.dart
  test/
    counter_test.dart

3. 创建一个要测试的类

3. Create a class to test

下一步,我们需要一个“单元”来测试。记住:“单元”是一个抽象的名称,它可以表示一个函数、方法或者类。本例中,我们会在 lib/counter.dart 文件中创建一个 Counter 类。它负责增加或减少一个从 0 开始的 value

Next, you need a “unit” to test. Remember: “unit” is another name for a function, method, or class. For this example, create a Counter class inside the lib/counter.dart file. It is responsible for incrementing and decrementing a value starting at 0.

class Counter {
  int value = 0;

  void increment() => value++;

  void decrement() => value--;
}

注意: 为了简化内容,本教程没有遵守“测试驱动开发”的写法。如果你擅长那种开发模式,当然可以选择用那种方式来写。

Note: For simplicity, this tutorial does not follow the “Test Driven Development” approach. If you’re more comfortable with that style of development, you can always go that route.

4. 为创建的类写一个测试

4. Write a test for our class

我们将在 counter_test.dart 文件中写第一个测试。使用顶级函数 test 来定义,可通过执行顶级函数 expect 来检查结果正确与否。这两个函数都来自 test 包。

Inside the counter_test.dart file, write the first unit test. Tests are defined using the top-level test function, and you can check if the results are correct by using the top-level expect function. Both of these functions come from the test package.

// Import the test package and Counter class
import 'package:test/test.dart';
import 'package:counter_app/counter.dart';

void main() {
  test('Counter value should be incremented', () {
    final counter = Counter();

    counter.increment();

    expect(counter.value, 1);
  });
}

5. 整合多个测试到一个 group

5. Combine multiple tests in a group

如果多个测试之间互相关联,可以使用 test 包提供的 group 函数将他们整合到一起。

If you have several tests that are related to one another, combine them using the group function provided by the test package.

import 'package:test/test.dart';
import 'package:counter_app/counter.dart';

void main() {
  group('Counter', () {
    test('value should start at 0', () {
      expect(Counter().value, 0);
    });

    test('value should be incremented', () {
      final counter = Counter();

      counter.increment();

      expect(counter.value, 1);
    });

    test('value should be decremented', () {
      final counter = Counter();

      counter.decrement();

      expect(counter.value, -1);
    });
  });
}

6. 执行测试

6. Run the tests

现在 Counter 类和它的测试都有了,开始执行测试!

Now that you have a Counter class with tests in place, you can run the tests.

用 IntelliJ 或 VSCode 执行测试

Run tests using IntelliJ or VSCode

IntelliJ 和 VSCode 的 Flutter 插件支持执行测试。用这种方式执行测试是最好的,因为它可以提供最快的反馈闭环,而且还支持断点调试。

The Flutter plugins for IntelliJ and VSCode support running tests. This is often the best option while writing tests because it provides the fastest feedback loop as well as the ability to set breakpoints.

  • IntelliJ

    1. 打开文件 counter_test.dart

      Open the counter_test.dart file

    2. 选择菜单 Run

      Select the Run menu

    3. 点击选项 Run 'tests in counter_test.dart'

      Click the Run 'tests in counter_test.dart' option

    4. 或者,也可以使用系统快捷键!

      Alternatively, use the appropriate keyboard shortcut for your platform.

  • VSCode

    1. 打开文件 counter_test.dart

      Open the counter_test.dart file

    2. 选择菜单 Debug

      Select the Debug menu

    3. 点击选项 Start Debugging

      Click the Start Debugging option

    4. 或者,也可以使用系统快捷键!

      Alternatively, use the appropriate keyboard shortcut for your platform.

在终端执行测试

Run tests in a terminal

我们也可以打开终端,在工程根目录输入以下命令来执行测试:

You can also use a terminal to run the tests by executing the following command from the root of the project:

flutter test test/counter_test.dart