Flutter集成测试插件flutter_gherkin_integration的使用
Flutter集成测试插件flutter_gherkin_integration的使用
简介
flutter_gherkin
是一个完全功能的Gherkin解析器和测试运行器。它适用于Flutter和Dart 2。
此实现尽可能接近其他Gherkin实现,并特别遵循各种形式的Cucumber。
作为Dart包可用:
flutter_gherkin: ^x.x.x
基本示例
以下是一个基本的Gherkin特征文件示例:
# Comment
Feature: Addition
@tag
Scenario: 1 + 0
Given I start with 1
When I add 0
Then I end up with 1
Scenario: 1 + 1
Given I start with 1
When I add 1
Then I end up with 2
使用integration_test
包的支持
注意:该库现在更倾向于使用integration_test
包和代码生成而不是flutter_driver
和运行时解释,并且flutter_driver
实现最终将被弃用。
入门步骤
- 在你的应用的
pubspec.yaml
文件中添加以下dev_dependencies
:
dev_dependencies:
integration_test:
build_runner:
flutter_gherkin:
- 添加以下
build.yaml
文件到项目的根目录。此文件允许Dart代码生成器针对你的应用lib
文件夹外的文件。
targets:
$default:
sources:
- lib/**
- pubspec.*
- $package$
# Allows the code generator to target files outside of the lib folder
- integration_test/**.dart
- 添加以下文件(和文件夹)
\test_driver\integration_test_driver.dart
。这是运行测试的入口点。更多信息参见:https://flutter.dev/docs/testing/integration-tests
import 'package:integration_test/integration_test_driver.dart' as integration_test_driver;
Future<void> main() {
// The Gherkin report data send back to this runner by the app after
// the tests have run will be saved to this directory
integration_test_driver.testOutputsDirectory = 'integration_test/gherkin/reports';
return integration_test_driver.integrationDriver(
timeout: Duration(minutes: 90),
);
}
-
创建一个名为
integration_test
的文件夹,这将包含所有Gherkin特征文件和生成的测试文件。 -
添加以下文件(和文件夹)
integration_test\features\counter.feature
,内容如下。这是一个基本的特征文件,可以转换为可运行测试的测试文件。
Feature: Counter
Scenario: User can increment the counter
Given I expect the "counter" to be "0"
When I tap the "increment" button
Then I expect the "counter" to be "1"
- 添加以下文件(和文件夹)
integration_test\gherkin_suite_test.dart
。注意属性@GherkinTestSuite()
,这表示代码生成器会为此文件创建一个部分文件,其中包含生成的Gherkin测试。不用担心初始错误,因为这些错误会在测试生成后消失。
import 'package:flutter_gherkin_integration/flutter_gherkin_integration_test.dart'; // 注意新的导入名称
import 'package:flutter_test/flutter_test.dart';
import 'package:gherkin/gherkin.dart';
// 要测试的应用程序。
import 'package:example_with_integration_test/main.dart' as app;
part 'gherkin_suite_test.g.dart';
@GherkinTestSuite()
void main() {
executeTestSuite(
FlutterTestConfiguration.DEFAULT([])
..reporters = [
StdoutReporter(MessageLevel.error)
..setWriteLineFn(print)
..setWriteFn(print),
ProgressReporter()
..setWriteLineFn(print)
..setWriteFn(print),
TestRunSummaryReporter()
..setWriteLineFn(print)
..setWriteFn(print),
JsonReporter(
writeReport: (_, __) => Future<void>.value(),
),
],
(World world) => app.main(),
);
}
- 我们现在需要通过在项目根目录下运行构建命令来生成测试。类似于
json_serializable
,这将创建一个.g.dart
部分文件,其中包含以代码格式呈现的Gherkin测试,可以通过使用integration_test
包来运行这些测试。
flutter pub run build_runner build
-
integration_test\gherkin_suite_test.dart
文件中的错误应该已经消失,你可以查看integration_test\gherkin_suite_test.g.dart
文件,其中包含了特征文件integration_test\features\counter.feature
中描述的Gherkin测试的编码版本。 -
我们现在可以从项目根目录下运行测试,使用以下命令:
flutter drive --driver=test_driver/integration_test_driver.dart --target=integration_test/gherkin_suite_test.dart
- 你可以通过在
integration_test\gherkin_suite_test.dart
文件的第12行设置断点并添加以下内容到你的.vscode\launch.json
文件来调试测试:
{
"name": "Debug integration_test",
"program": "test_driver/integration_test_driver.dart",
"cwd": "example_with_integration_test/",
"request": "launch",
"type": "dart",
"args": [
"--target=integration_test/gherkin_suite_test.dart",
],
}
-
自定义世界需要扩展
FlutterWorld
,注意FlutterDriverWorld
。 -
如果你更改了任何特征文件,你需要使用以下命令重新生成测试:
# 你可能需要首先运行清理命令,如果你刚刚更改了特征文件
flutter pub run build_runner clean
flutter pub run build_runner build
包升级注意事项
该包即将有一个主要版本来支持null-safety,然后另一个主要版本来支持使用integration_test
包和WidgetTester
运行测试。我们仍将保持与使用flutter_driver
运行测试的兼容性,并尽最大努力使切换到使用integration_test
包变得无缝。由于我们必须重构大量代码,因此不幸的是,一些不可避免的破坏性变化将会发生。
目录
入门
请参阅https://docs.cucumber.io/gherkin/了解有关Gherkin语法和行为驱动开发(BDD)的信息。
请参阅示例说明文档,以获取快速入门指南,了解如何运行示例特性和应用程序。
第一步是创建一个启用Flutter驱动程序的应用版本,以便可以自动化。一个很好的指导如何做到这一点可以在这里找到。但是简单来说,在你的项目中创建一个名为test_driver
的文件夹,并在其中创建一个名为app.dart
的文件,并粘贴以下代码:
import '../lib/main.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_driver/driver_extension.dart';
void main() {
// 这一行启用了扩展
enableFlutterDriverExtension();
// 调用你的应用的`main()`函数或调用`runApp`与任何你想测试的小部件。
runApp(MyApp());
}
这段代码只是启用了Flutter驱动程序扩展,这是自动化应用所必需的,然后运行你的应用。
要开始使用Flutter进行BDD,第一步是编写一个特征文件并在其中写一个测试场景。
首先创建一个名为test_driver
的文件夹(这与当前的集成测试一致,因为我们需要使用Flutter驱动程序来自动化应用)。在文件夹内创建一个名为features
的文件夹,然后创建一个名为counter.feature
的文件。
Feature: Counter
The counter should be incremented when the button is pressed.
Scenario: Counter increases when the button is pressed
Given I expect the "counter" to be "0"
When I tap the "increment" button 10 times
Then I expect the "counter" to be "10"
现在我们已经创建了一个场景,我们需要实现场景中的步骤。步骤只是继承自基础步骤定义类或其任何变体Given
、Then
、When
、And
、But
的类。
虽然示例有些牵强,但它展示了过程。
此库有一些内置的步骤定义,方便使用。第一个步骤使用了内置的步骤,但第二个步骤When I tap the "increment" button 10 times
是一个自定义步骤,必须实现。要实现一个步骤,我们需要创建一个简单的步骤定义类。
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
StepDefinitionGeneric TapButtonNTimesStep() {
return when2<String, int, FlutterWorld>(
'I tap the {string} button {int} times',
(key, count, context) async {
final locator = find.byValueKey(key);
for (var i = 0; i < count; i += 1) {
await FlutterDriverUtils.tap(context.world.driver, locator);
}
},
);
}
可以看到,when2
方法被调用,指定了两个输入参数。第三个类型FlutterWorld
是一个特殊的上下文对象,允许从上下文对象访问Flutter驱动程序,从而与你的应用交互。如果你不需要自定义上下文对象或强类型参数,可以完全省略类型参数。
输入参数是通过正则表达式模式从已知参数类型{string}
和{int}
中检索的。它们只是特殊的语法,表示你在步骤文本的这些位置期望字符串和整数。因此,当要执行的步骤是When I tap the "increment" button 10 times
时,参数"increment"
和10
将以正确的类型传递给步骤。请注意,在模式中你可以使用任何正则表达式捕获组来指示任何输入参数。例如,正则表达式RegExp(r"When I tap the {string} (button|icon) {int} times")
表示3个参数,并且会匹配以下步骤文本中的任意一项:
When I tap the "increment" button 10 times // 传递3个参数 "increment", "button" & 10
When I tap the "plus" icon 2 times // 传递3个参数 "plus", "icon" & 2
值得注意的是,此库不依赖于镜子(反射),原因有很多,但主要是为了便于维护,并符合Flutter不允许反射的原则。总的来说,这使得代码更容易理解和维护,也更容易为用户调试。缺点是我们必须稍微明确地提供自定义代码实例,如步骤定义、钩子、报告器和自定义参数。
现在我们有了一个可测试的应用、一个特征文件和一个自定义步骤定义,我们需要创建一个类来调用此库并实际运行测试。创建一个名为app_test.dart
的文件,并插入以下代码:
import 'dart:async';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
import 'hooks/hook_example.dart';
import 'steps/colour_parameter.dart';
import 'steps/given_I_pick_a_colour_step.dart';
import 'steps/tap_button_n_times_step.dart';
Future<void> main() {
final config = FlutterTestConfiguration()
..features = [RegExp('features/*.*.feature')]
..reporters = [
ProgressReporter(),
TestRunSummaryReporter(),
JsonReporter(path: './report.json')
] // 可以包括 "StdoutReporter()" 无需消息级别参数即可获得详细的日志信息
..hooks = [HookExample()]
..stepDefinitions = [TapButtonNTimesStep(), GivenIPickAColour()]
..customStepParameterDefinitions = [ColourParameter()]
..restartAppBetweenScenarios = true
..targetAppPath = "test_driver/app.dart";
// ..tagExpression = "@smoke" // 取消注释以查看基于标签表达式的示例
return GherkinRunner().execute(config);
}
这段代码简单地创建了一个配置对象,并调用此库,该库将立即解析你的特征文件并运行测试。配置文件非常重要,并将在下文中进一步详细说明。然而,所有操作只是提供了一个RegExp
,指定一个或多个特征文件的路径,设置了报告器为ProgressReporter
报告,打印场景和步骤的结果到标准输出(控制台)。TestRunSummaryReporter
在所有测试执行完成后打印运行摘要。最后,它指定了上述创建的可测试应用的路径test_driver/app.dart
。重要的是,它指示库运行测试时应针对哪个应用。
最后,要在命令行上运行测试,请运行以下命令:
dart test_driver/app_test.dart
有关调试测试的信息,请参阅调试。
注:你可能需要确保dart可通过将其添加到路径变量来访问。
配置
配置是此库中的重要组成部分,因为它不仅指定了要运行的内容,还指定了要运行的步骤、钩子和报告器的类。与其他实现不同,此库不依赖于反射,因此需要显式告知要使用的类。
可以在配置文件中指定以下参数:
特征文件
必需
一个Pattern
的迭代器,指定要运行的*.feature
文件的位置。请参阅:https://api.dart.dev/stable/2.12.4/dart-core/Pattern-class.html
标签表达式
默认值为null
。
一个中缀布尔表达式,用于根据其标签定义要运行的功能和场景。参见标签。
排序
默认值为ExecutionOrder.random
场景运行的顺序。随机顺序可能突出显示任何应修复的测试间依赖关系。使用ExecutionOrder.sorted
按filename
顺序处理特征文件。
步骤定义
默认值为Iterable<StepDefinitionBase>
放置任何自定义步骤定义类的实例,这些类与特征文件中定义的任何自定义步骤匹配。
import 'dart:async';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
import 'steps/given_I_pick_a_colour_step.dart';
import 'steps/tap_button_n_times_step.dart';
Future<void> main() {
final config = FlutterTestConfiguration()
..features = [RegExp('features/*.*.feature')]
..reporters = [StdoutReporter()]
..stepDefinitions = [TapButtonNTimesStep(), GivenIPickAColour()]
..restartAppBetweenScenarios = true
..targetAppPath = "test_driver/app.dart";
return GherkinRunner().execute(config);
}
默认语言
默认值为en
这指定了特征文件的默认语言。请参阅:https://cucumber.io/docs/gherkin/reference/#overview了解支持的语言。
请注意,这可以在特征文件本身中通过语言块覆盖。
# language: de
Funktionalität: Calculator
Tests the addition of two numbers
Szenariogrundriss: Add two numbers
Gegeben sei the numbers <number_one> and <number_two>
Wenn they are added
Dann the expected result is <result>
Beispiele:
| number_one | number_two | result |
| 12 | 5 | 17 |
| 20 | 5 | 25 |
| 20937 | 1 | 20938 |
| 20.937 | -1.937 | 19 |
# language: fr
Fonctionnalité: Counter
The counter should be incremented when the button is pressed.
@smoke
Scénario: Counter increases when the button is pressed
Etant donné que I pick the colour red
Et I expect the "counter" to be "0"
Quand I tap the "increment" button 10 times
Alors I expect the "counter" to be "10"
自定义步参数定义
默认值为CustomParameter<dynamic>
。
放置任何自定义步参数的实例。这些将在场景运行时与步骤匹配,并将其结果传递给可执行步骤。请参阅自定义参数。
import 'dart:async';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
import 'steps/given_I_pick_a_colour_step.dart';
import 'steps/tap_button_n_times_step.dart';
import 'steps/colour_parameter.dart';
Future<void> main() {
final config = FlutterTestConfiguration()
..features = [RegExp('features/*.*.feature')]
..reporters = [StdoutReporter()]
..stepDefinitions = [TapButtonNTimesStep(), GivenIPickAColour()]
..customStepParameterDefinitions = [ColourParameter()]
..restartAppBetweenScenarios = true
..targetAppPath = "test_driver/app.dart";
return GherkinRunner().execute(config);
}
钩子
钩子是一段可在测试运行的某些点处执行的自定义代码。钩子可以在以下测试运行点处运行:
- 测试运行前
- 所有测试完成后
- 每个场景之前
- 每个场景之后
创建一个钩子很简单。只需继承Hook
并重写表示您希望在过程中运行代码的点的方法。请注意,并非所有方法都需要重写,只需重写需要运行自定义代码的点。
import 'package:gherkin/gherkin.dart';
class HookExample extends Hook {
/// 为该钩子分配优先级。
/// 优先级高的先运行,所以优先级为10的先运行,优先级为2的后运行
@override
int get priority => 1;
/// 在任何场景在测试运行前执行
@override
Future<void> onBeforeRun(TestConfiguration config) async {
print("before run hook");
}
/// 在所有场景在测试运行后完成时执行
@override
Future<void> onAfterRun(TestConfiguration config) async {
print("after run hook");
}
/// 在场景及其步骤执行前运行
@override
Future<void> onBeforeScenario(
TestConfiguration config, String scenario) async {
print("running hook before scenario '$scenario'");
}
/// 在场景执行后运行
@override
Future<void> onAfterScenario(
TestConfiguration config, String scenario) async {
print("running hook after scenario '$scenario'");
}
}
最后确保在配置文件中的钩子集合中添加该钩子。
import 'dart:async';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
import 'hooks/hook_example.dart';
import 'steps/given_I_pick_a_colour_step.dart';
import 'steps/tap_button_n_times_step.dart';
Future<void> main() {
final config = FlutterTestConfiguration()
..features = [RegExp('features/*.*.feature')]
..reporters = [ProgressReporter()]
..hooks = [HookExample()]
..stepDefinitions = [TapButtonNTimesStep(), GivenIPickAColour()]
..restartAppBetweenScenarios = true
..targetAppPath = "test_driver/app.dart";
return GherkinRunner().execute(config);
}
附件
附件是你可以在运行场景时附加的数据。这可能是简单的文本数据,甚至是截图这样的图像。这些附件可以由报告器用来提供更多的上下文信息。例如,当一个步骤失败时,可以附加一些上下文信息到场景中,然后由报告器用来显示为什么步骤失败。
附件通常通过钩子(例如onAfterStep
)附加。
import 'package:gherkin/gherkin.dart';
class AttachScreenshotOnFailedStepHook extends Hook {
/// 在步骤执行后运行
@override
Future<void> onAfterStep(World world, String step, StepResult stepResult) async {
if (stepResult.result == StepExecutionResult.fail) {
world.attach('Some info.','text/plain');
world.attach('{"some", "JSON"}}', 'application/json');
}
}
}
截图
为了在步骤失败时拍摄截图,你可以使用预定义的钩子AttachScreenshotOnFailedStepHook
并将其包含在测试配置的钩子配置中。这个钩子将拍摄截图并作为附件添加到场景中。如果使用JsonReporter
,截图将嵌入到报告中,可以用来生成HTML报告,最终会在失败的步骤下显示截图。
import 'dart:async';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
import 'hooks/hook_example.dart';
import 'steps/colour_parameter.dart';
import 'steps/given_I_pick_a_colour_step.dart';
import 'steps/tap_button_n_times_step.dart';
Future<void> main() {
final config = FlutterTestConfiguration()
..features = [RegExp('features/*.*.feature')]
..reporters = [
ProgressReporter(),
TestRunSummaryReporter(),
JsonReporter(path: './report.json')
]
..hooks = [HookExample(), AttachScreenshotOnFailedStepHook()]
..stepDefinitions = [TapButtonNTimesStep(), GivenIPickAColour()]
..customStepParameterDefinitions = [ColourParameter()]
..restartAppBetweenScenarios = true
..targetAppPath = "test_driver/app.dart";
return GherkinRunner().execute(config);
}
报告器
报告器是可以报告测试运行状态的类。这可以简单地将场景结果记录到控制台。该库有一系列内置报告器:
StdoutReporter
:将所有来自测试运行的消息记录到标准输出(控制台)。ProgressReporter
:记录测试运行进度,标记每个场景的步骤为通过、跳过或失败。JsonReporter
:创建一个包含测试运行结果的JSON文件,然后可以使用’https://www.npmjs.com/package/cucumber-html-reporter.'来生成HTML报告。你可以传递要创建的JSON文件的路径。
你应该在配置中提供至少一个报告器,否则很难知道发生了什么。
注:欢迎PR新的报告器!
import 'dart:async';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'steps/colour_parameter.dart';
import 'steps/given_I_pick_a_colour_step.dart';
import 'steps/tap_button_n_times_step.dart';
Future<void> main() {
final config = FlutterTestConfiguration()
..features = [RegExp('features/*.*.feature')]
..reporters = [StdoutReporter()]
..stepDefinitions = [TapButtonNTimesStep(), GivenIPickAColour()]
..customStepParameterDefinitions = [ColourParameter()]
..restartAppBetweenScenarios = true
..targetAppPath = "test_driver/app.dart";
return GherkinRunner().execute(config);
}
创建世界
默认值为null
。
虽然不建议在同一个场景中共享步骤之间的状态,但我们生活在现实世界中,因此有时可能需要共享某些信息,例如登录凭证等,以便后续步骤使用。世界上下文对象是在每个场景中创建一次,并在每个场景结束时销毁。此配置属性允许你指定一个自定义的World
类来创建,然后可以在你的步骤类中访问它。
import 'dart:async';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'steps/given_I_pick_a_colour_step.dart';
import 'steps/tap_button_n_times_step.dart';
Future<void> main() {
final config = FlutterTestConfiguration()
..features = [RegExp('features/*.*.feature')]
..reporters = [StdoutReporter()]
..stepDefinitions = [TapButtonNTimesStep(), GivenIPickAColour()]
..createWorld = (TestConfiguration config) async => await createMyWorldInstance(config)
..restartAppBetweenScenarios = true
..targetAppPath = "test_driver/app.dart";
return GherkinRunner().execute(config);
}
记录Flutter进程输出
默认值为false
如果为true
,Flutter进程的输出将记录到stdout / stderr流。在调试应用构建或启动故障时很有用。
Flutter构建超时
默认值为90秒
指定等待Flutter构建完成、安装应用并进入可测试状态的时间。较慢的机器可能需要超过默认的90秒才能完成此过程。
在Flutter驱动程序连接到应用之前
一个异步方法,当Flutter驱动程序尝试连接到正在测试的应用之前调用。
在Flutter驱动程序成功连接到应用之后
一个异步方法,当Flutter驱动程序成功连接到正在测试的应用之后调用。
Flutter驱动程序最大连接尝试次数
默认值为3
指定在测试中断之前对正在运行的应用尝试连接的Flutter驱动程序的最大次数。
Flutter驱动程序重新连接延迟
默认值为2秒
指定在Flutter驱动程序连接尝试失败后等待的时间,以重新连接到正在运行的应用。
特定于Flutter的配置选项
FlutterTestConfiguration
将自动创建一些默认的Flutter选项,如众所周知的步骤定义、提供对Flutter驱动程序实例的访问的Flutter世界上下文对象,以及在场景之间重启您的测试应用的能力。大多数情况下,如果您正在测试Flutter应用,应使用此配置对象。
在场景之间重启应用
默认值为true
。
为了避免测试在一个由先前测试更改的应用上开始,建议在每个场景之间重启正在测试的Flutter应用。虽然这将略微增加执行时间,但将限制测试因运行在一个由先前测试更改的应用上而失败的情况。请注意,在更复杂的应用中,可能还需要使用AfterScenario
钩子将应用重置到测试可以运行的基础状态。例如,如果重启应用会导致锁屏,则需要注销。
目标应用路径
默认值为lib/test_driver/app.dart
这应该指向能够启用Flutter驱动程序扩展的可测试应用,从而能够自动化。当测试运行开始时,此应用将启动,并且如果restartAppBetweenScenarios
配置属性设置为true
,则将重新启动。
构建
默认值为true
此可选参数让你指定是否应在运行第一个测试之前构建目标应用。这默认为true
。
在测试结束后保持应用运行
默认值为false
此可选参数将在测试完成后保持Flutter应用运行。这默认为false
。
构建风味
默认为空字符串
此可选参数让你指定要测试的Flutter风味。Flutter的风味类似于Android Build Variants
或iOS Scheme Configuration
。关于Flutter和Android/iOS方面的完整指南,请参阅flavoring flutter文档。
构建模式
默认值为BuildMode.Debug
此可选参数让你指定在编译应用时偏好的构建模式。Flutter Gherkin支持--debug
和--profile
模式。更多详情请参阅Flutter的构建模式文档。
dartDefineArgs
默认值为[]
传递给构建参数的--dart-define
参数。包括每个参数的名称和值。例如,--dart-define=MY_VAR="true"
变成['MY_VAR="true"']
。
目标设备ID
默认为空字符串
此可选参数允许你指定设备的目标ID,如同flutter run --device-id
命令。要列出已连接的设备,请运行flutter devices
。如果你只有一个设备连接,则不需要提供此参数。
应用运行协议端点URI
一个观察者URL,测试运行器可以连接到而不是创建新的正在运行的应用实例
该URL的形式为http://127.0.0.1:51540/EM72VtRsUV0=/
,并且通常在标准输出中以Connecting to service protocol: http://127.0.0.1:51540/EM72VtRsUV0=/
的形式打印出来。
你需要在启动Flutter应用时添加--verbose
标志才能看到此输出,并确保运行的应用调用了enableFlutterDriverExtension()
。
特征文件
步骤定义
步骤定义是特征文件中一个文本步骤的编码表示。每个步骤都以Given
、Then
、When
、And
或But
开头。需要注意的是,所有的步骤实际上是相同的,但在语义上有所不同。关键字在匹配步骤时不考虑。因此,下面两个步骤实际上被视为相同,并将导致调用相同的步骤定义。
注意:在本实现中,步骤最多允许5个输入参数。如果你发现自己需要更多,你可能需要考虑将步骤做得更独立或者使用Table
参数。
Given there are 6 kangaroos
Then there are 6 kangaroos
然而,你选择的领域语言会影响在每个上下文中最佳的工作关键字。更多信息请参阅:https://docs.cucumber.io/gherkin/reference/#steps。
Given
Given
步骤用于描述系统的初始状态。执行一个Given
步骤通常会将系统置于一个明确定义的状态。
要实现一个Given
步骤,你可以继承Given
类。
Given Bob has logged in
实现如下:
import 'package:gherkin/gherkin.dart';
StepDefinitionGeneric GivenWellKnownUserIsLoggedIn() {
return given1(
RegExp(r'(Bob|Mary|Emma|Jon) has logged in'),
(wellKnownUsername, context) async {
// 实现你的代码
},
);
}
如果在一个块中需要多个Given
,最好使用附加的关键字And
或But
。
Given Bob has logged in
And opened the dashboard
Then
Then
步骤用于描述预期的结果或结果。它们通常包含一个断言,可以是通过或失败的。
Then I expect 10 apples
实现如下:
import 'package:gherkin/gherkin.dart';
StepDefinitionGeneric ThenExpectAppleCount() {
return then1(
'I expect {int} apple(s)',
(count, context) async {
// 示例代码
final actualCount = await _getActualCount();
context.expectMatch(actualCount, count);
},
);
}
断言
注意
expect
库目前仅在其自己的test
函数块中工作;因此,如果将其与Then
步骤一起使用,将导致错误。因此,添加了expectMatch
或expectA
或this.expect
或context.expect
方法,这些方法模仿了except
的基本功能,即断言给定的条件为真。Dart
测试库中的Matcher
仍然可以使用。
步骤超时
默认情况下,如果步骤超出配置文件中的defaultTimeout
参数,步骤将超时。在某些情况下,你可能希望拥有一个较长或较短的运行步骤,因此在这种情况下,你可以选择性地为该步骤提供自定义超时。要做到这一点,需要在步骤的super
调用中传入一个Duration
对象。
例如,下面的代码将步骤的超时设置为10秒。
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_gherkin_integration/flutter_gherkin.dart';
import 'package:gherkin/gherkin.dart';
StepDefinitionGeneric TapButtonNTimesStep() {
return given2<String, int, FlutterWorld>(
'I tap the {string} button {int} times',
(key, count, context) async {
final locator = find.byValueKey(key);
for (var i = 0; i < count; i += 1) {
await FlutterDriverUtils.tap(context.world.driver, locator);
}
},
);
}
多行字符串
多行字符串可以跟随步骤,并将作为最终参数传递给该步骤。要表示一个多行字符串,前缀和后缀可以是第三双引号或单引号""" ... """
或''' ... '''
。
例如:
Given I provide the following "review" comment
"""
Some long review comment.
That can span multiple lines
Skip lines
Maybe even include some numbers
1
2
3
"""
匹配的步骤定义将是:
import 'package:gherkin/gherkin.dart';
StepDefinitionGeneric GivenTheMultiLineComment() {
return given1(
'I provide the following {string} comment',
(comment, context) async {
// 实现步骤
},
);
}
数据表
import 'package:gherkin/gherkin.dart';
/// 此步骤期望一个跟在其后的多行字符串
///
/// 例如:
///
/// `When I add the users`
/// | Firstname | Surname | Age | Gender |
/// | Woody | Johnson | 28 | Male |
/// | Edith | Summers | 23 | Female |
/// | Megan | Hill | 83 | Female |
StepDefinitionGeneric WhenIAddTheUsers() {
return when1(
'I add the users',
(Table dataTable, context) async {
for (var row in dataTable.rows) {
// 对每一行做些事情
row.columns.forEach((columnValue) => print(columnValue));
}
// 或者将表格作为映射(列值由标题键入)
final columns = dataTable.asMap();
final personOne = columns.elementAt(0);
final personOneName = personOne["Firstname"];
print('Name of first user: `$personOneName` ');
},
);
}
更多关于Flutter集成测试插件flutter_gherkin_integration的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter集成测试插件flutter_gherkin_integration的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_gherkin_integration
是一个用于 Flutter 集成测试的插件,它允许你使用 Gherkin 语法编写行为驱动开发(BDD)风格的测试。Gherkin 是一种自然语言风格的语法,通常用于描述软件的行为和功能。通过使用 flutter_gherkin_integration
,你可以在 Flutter 项目中编写和执行 Gherkin 风格的集成测试。
以下是如何在 Flutter 项目中使用 flutter_gherkin_integration
的步骤:
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 flutter_gherkin_integration
依赖。
dev_dependencies:
flutter_gherkin_integration: ^1.0.0
flutter_test:
sdk: flutter
然后运行 flutter pub get
以安装依赖。
2. 创建 Gherkin 文件
在 test
目录下创建一个新的目录,例如 features
,并在其中创建 .feature
文件。例如,创建一个 login.feature
文件:
Feature: Login Feature
As a user
I want to login to the app
So that I can access my account
Scenario: Successful login
Given I am on the login screen
When I enter "username" in the username field
And I enter "password" in the password field
And I press the login button
Then I should see the home screen
3. 编写步骤定义
在 test
目录下创建一个 steps
目录,并在其中创建 login_steps.dart
文件。在该文件中,你将定义 Gherkin 步骤的实现。
import 'package:flutter_gherkin_integration/flutter_gherkin_integration.dart';
import 'package:flutter_test/flutter_test.dart';
class LoginSteps extends Given {
@override
Future<void> executeStep() async {
// 实现 Given 步骤
expect(find.text('Login Screen'), findsOneWidget);
}
}
class EnterUsername extends When {
@override
Future<void> executeStep(String username) async {
// 实现 When 步骤
await tester.enterText(find.byType(TextField), username);
}
}
class EnterPassword extends When {
@override
Future<void> executeStep(String password) async {
// 实现 When 步骤
await tester.enterText(find.byType(TextField), password);
}
}
class PressLoginButton extends And {
@override
Future<void> executeStep() async {
// 实现 And 步骤
await tester.tap(find.text('Login'));
await tester.pump();
}
}
class SeeHomeScreen extends Then {
@override
Future<void> executeStep() async {
// 实现 Then 步骤
expect(find.text('Home Screen'), findsOneWidget);
}
}
4. 配置测试运行器
在 test
目录下创建一个 test_driver
目录,并在其中创建 gherkin_test.dart
文件。在该文件中,你将配置 Gherkin 测试运行器。
import 'package:flutter_gherkin_integration/flutter_gherkin_integration.dart';
import 'package:flutter_test/flutter_test.dart';
import '../steps/login_steps.dart';
void main() {
final config = FlutterTestConfiguration()
..features = ['test/features/login.feature']
..steps = [
LoginSteps(),
EnterUsername(),
EnterPassword(),
PressLoginButton(),
SeeHomeScreen(),
];
executeTests(config);
}
5. 运行测试
你可以使用以下命令运行集成测试:
flutter drive --target=test_driver/gherkin_test.dart