Flutter单元测试插件given_when_then_unit_test的使用
Flutter单元测试插件given_when_then_unit_test的使用
given_when_then_unit_test
是一个用于创建更具可读性测试的Flutter包。它可以帮助你以更自然的语言编写单元测试,使测试代码更加优雅且易于理解。
特性
提高测试代码的可读性
通过使用 given_when_then
插件,你可以将测试逻辑用接近英语句子的方式表达出来,从而提高代码的可读性。例如:
// Without `given_when_then`
group('calculator', () {
// ...
group('add 1', () => calc.add(1), then: () {
test('result should be 1', () {
// ...
});
group('[and] subtract 1', () => calc.subtract(1), body: () {
test('res should be 0', () {
// ...
});
});
});
});
// 🔥 With `given_when_then` as a common English sentence
given('calculator', () {
// ...
when('add 1', () => calc.add(1), then: () {
then('result should be 1', () {
// ...
});
when('[and] subtract 1', () => calc.subtract(1), body: () {
then('res should be 0', () {
// ...
});
});
});
});
结合 shouldly
包可以进一步增强代码的可读性:
given('calculator', () {
late Calculator calc;
before(() {
calc = Calculator();
});
when('add 1', () {
before(() => calc.add(1));
then('result should be 1', () {
calc.res.should.be(1);
});
and('subtract 1', () {
before(() => calc.subtract(1));
then('res should be 0', () {
calc.res.should.beZero();
});
});
});
});
自动生成BDD风格的测试消息
使用 given_when_then
可以自动生成更具描述性的测试消息,而无需额外的工作:
✓ Given empty calculator When add 1 Then result should be 1
✓ Given empty calculator When add 1 and subtract 1 Then res should be 0
使用方法
简单示例
不使用 given_when_then
group('empty calculator', body: () {
late Calculator calc;
setUp(() {
calc = Calculator();
});
group('add 1', () {
setUp(() {
calc.add(1);
});
test('result should be 1', () {
calc.res.should.be(1);
});
group('[and] subtract 1', () {
setUp(() {
calc.subtract(1);
});
test('res should be 0', () {
calc.res.should.beZero();
});
});
});
});
使用 given_when_then
given('empty calculator', () {
late Calculator calc;
before(() {
calc = Calculator();
});
when('add 1', () => calc.add(1), then: () {
then('result should be 1', () {
calc.res.should.be(1);
});
and('subtract 1', () => calc.subtract(1), body: () {
then('res should be 0', () {
calc.res.should.beZero();
});
});
});
});
高级示例:使用模拟对象(Mocking)
given('Post Controller', body: () {
late PostController postController;
late IPostRepository mockPostRepository;
late IToastr mockToastr;
before(() {
mockPostRepository = MockPostRepository();
mockToastr = MockToastr();
postController = PostController(
repo: mockPostRepository,
toastr: mockToastr,
);
});
whenn('save new valid post', () {
bool? saveResult;
before(() async {
when(() => mockPostRepository.addNew('new post'))
.thenAnswer((_) => Future.value(true));
saveResult = await postController.addNew('new post');
});
then('should return true', () async {
saveResult.should.beTrue();
});
then('toastr shows success', () async {
verify(() => mockToastr.success('ok')).called(1);
});
});
whenn('save new invalid post', () {
bool? saveResult;
before(() async {
when(() => mockPostRepository.addNew('new invalid post'))
.thenAnswer((_) => Future.value(false));
saveResult = await postController.addNew('new invalid post');
});
then('should return false', () async {
saveResult.should.beFalse();
});
then('toastr shows error', () async {
verify(() => mockToastr.error('invalid post')).called(1);
});
});
});
测试用例
有多种方式来使用测试用例:
版本1
testCases([
const TestCase([1, 1, 2]),
const TestCase([5, 3, 8])
], (testCase) {
final x = testCase.args[0] as int;
final y = testCase.args[1] as int;
given('two numbers $x and $y', () {
when('summarizing them', () {
then('the result should be equal to ${testCase.args.last}', () {
(x + y).should.be(testCase.args[2] as int);
});
});
});
});
版本2 - 使用泛型
testCases2<String, String>([
const TestCase2('Flutter', 'F'),
const TestCase2('Awesome', 'A'),
], (args) {
test('Word ${args.arg1} start with ${args.arg2}', () {
args.arg1.should.startWith(args.arg2);
});
});
格式化测试报告
你可以通过设置变量 GivenWhenThenOptions.pads
来格式化测试报告,使其在一行或每行打印每个步骤:
GivenWhenThenOptions.pads = 4;
结果如下:
Given the account balance is $100
And the card is valid
And the machine contains enough money
When the Account Holder requests $20
Then the Cashpoint should dispense
And the account balance should be $80
And the card should be returned
已知问题
- 与
mocktail
或mockito
包冲突,因为它们也引入了when
方法。可以通过隐藏when
并使用whenn
来解决此问题:
import 'package:mocktail/mocktail.dart' hide when;
import 'package:mocktail/mocktail.dart' as mktl show when;
示例代码
以下是一个完整的示例代码,展示了如何使用 given_when_then_unit_test
和 shouldly
包进行单元测试:
// ignore_for_file: public_member_api_docs
import 'package:given_when_then_unit_test/given_when_then_unit_test.dart';
import 'package:shouldly/shouldly.dart';
import 'package:test/test.dart';
class Calculator {
num _val = 0;
num get res => _val;
void add(num value) {
_val = _val + value;
}
void subtract(int value) {
_val = _val - value;
}
}
void main() {
group('calculator', () {
late Calculator calc;
setUp(() => calc = Calculator());
group('add 1', () {
setUp(() => calc.add(1));
test('result should be 1', () {
expect(calc.res, 1);
});
group('[and] substract 1', () {
setUp(() => calc.subtract(1));
test('res should be 0', () {
expect(calc.res, isZero);
});
});
});
});
// You can rewrite tests above with Given When Then + Shouldly as a common English sentence
given('calculator', () {
late Calculator calc;
before(() {
calc = Calculator();
});
when('add 1', () {
before(() => calc.add(1));
then('result should be 1', () {
calc.res.should.be(1);
});
and('subtract 1', () {
before(() => calc.subtract(1));
then('res should be 0', () {
calc.res.should.beZero();
});
});
});
});
}
希望这些内容能帮助你更好地理解和使用 given_when_then_unit_test
插件!如果你有任何问题或需要进一步的帮助,请随时提问。
更多关于Flutter单元测试插件given_when_then_unit_test的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter单元测试插件given_when_then_unit_test的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用given_when_then_unit_test
插件来进行单元测试的示例代码。given_when_then_unit_test
插件并不是一个官方或广泛认可的插件,但基于你提到的命名约定,我们可以使用Flutter的test
包和一些常见的测试模式来模拟这个流程。
在Flutter中,我们通常使用test
包来进行单元测试,结合given_when_then
的结构可以让测试代码更加清晰和易于理解。以下是一个简单的示例,展示了如何使用test
包来编写符合given_when_then
结构的单元测试。
1. 添加依赖
首先,确保你的pubspec.yaml
文件中包含了test
依赖(Flutter项目默认已经包含)。
dev_dependencies:
test: ^1.19.0 # 请检查最新版本
2. 编写被测函数
假设我们有一个简单的计数器函数increment
,它接受一个整数并返回增加1的结果。
// counter.dart
int increment(int value) {
return value + 1;
}
3. 编写单元测试
接下来,我们编写单元测试,使用given_when_then
的结构来组织代码。
// counter_test.dart
import 'package:test/test.dart';
import 'counter.dart';
void main() {
test('increment function works as expected', () {
// given
int initialValue = 5;
int expectedValue = 6;
// when
int result = increment(initialValue);
// then
expect(result, equals(expectedValue));
});
}
4. 运行测试
你可以使用命令行工具来运行测试:
flutter test test/counter_test.dart
或者,如果你使用的是IDE(如VS Code),你可以直接点击测试文件旁边的运行按钮来执行测试。
解释
- given:设置测试的前提条件或输入值。在这个例子中,我们设置了
initialValue
为5。 - when:执行被测函数。在这个例子中,我们调用了
increment
函数。 - then:验证结果是否符合预期。在这个例子中,我们使用
expect
函数来检查increment
函数的返回值是否为6。
通过这种方式,你的单元测试代码将更加清晰和结构化,便于理解和维护。虽然given_when_then_unit_test
不是一个具体的Flutter插件,但你可以通过上述方式在Flutter项目中实现类似的测试结构。