Flutter错误处理插件expect_error的使用

Flutter错误处理插件expect_error的使用

expect_error是一个受TypeScript的// @expect-error启发的测试库,旨在帮助包作者测试编译错误。以下是如何在Flutter项目中使用它的详细指南。

使用方法

expect_error提供了一个compiles匹配器,可以在单元测试中使用。下面是一个简单的例子:

// test/my_test.dart
import 'package:expect_error/expect_error.dart';
import 'package:test/test.dart';

void main() async {
  final library = await Library.parseFromStacktrace();

  test('String is not assignable to int', () async {
    await expectLater(library.withCode('''
// expect-error: INVALID_ASSIGNMENT
int value = "string";
'''), compiles);
  });
}

这个例子测试了以下代码是否会产生编译错误"INVALID_ASSIGNMENT":

int value = "string";

FAQ:为什么在代码块中使用注释而不是匹配器?

你可能会问为什么这样写:

await expectLater(library.withCode('''
// expect-error: INVALID_ASSIGNMENT
int value = "string";
'''), compiles);

比这样写更好:

await expectLater(library.withCode('''
int value = "string";
'''), throwsCompilationError('INVALID_ASSIGNMENT'));

原因是expect_error依赖于注释来明确错误的位置。当使用// expect-error: x时,只有下一行可以产生编译错误。

例如,如果这样做:

await expectLater(library.withCode('''
void main() {
  // expect-error: INVALID_ASSIGNMENT
  print('a');
  int value = "string";
}
'''), compiles);

这个测试会失败,因为虽然代码块确实包含一个INVALID_ASSIGNMENT错误,但该错误不在print语句上,而是在int value = "string"上。

为了修复测试,我们需要将注释放在错误行之前:

await expectLater(library.withCode('''
void main() {
  print('a');
  // expect-error: INVALID_ASSIGNMENT
  int value = "string";
}
'''), compiles);

指定多个错误代码

可以通过用逗号分隔来指定多个错误代码:

await expectLater(library.withCode(r'''
String fn(int a) => '';

// expect-error: NOT_ENOUGH_POSITIONAL_ARGUMENTS, INVALID_ASSIGNMENT
int a = fn();
'''), compiles);

在代码块中导入文件/包

可以在代码块中使用import指令导入Dart代码:

await expectLater(library.withCode(r'''
import 'package:riverpod/riverpod.dart';

final provider = Provider<int>((ref) {
  // expect-error: INVALID_ASSIGNMENT
  return 'string';
});
'''), compiles);

Flutter支持

由于expect_error是基于analyzer包构建的,因此一个包不能同时依赖Flutter和expect_error。要在与Flutter交互时使用expect_error进行编译错误测试,需要一个变通方案。

例如,考虑一个依赖Flutter的包my_package,它暴露了一个MyWidget类:

// my_package/lib/my_widget.dart
import 'package:flutter/material.dart';

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key, required String parameter}) : super(key: key);

  // ...
}

为了测试这个MyWidget类,而不是在my_package/test文件夹中添加测试,我们可以创建一个新的Dart项目,使文件结构如下:

my_package
  puspec.yaml
  lib
    my_widget.dart
  expect_error_test
    pubspec.yaml
    test
      my_widget_test.dart

这个expect_error_test应用会依赖于expect_error

name: expect_error_test
---
dev_dependencies:
  expect_error: ...

然后,在expect_error_test/test/my_widget_test中,可以这样做:

void main() async {
  final flutterLibrary = await Library.custom(
    packageName: 'my_package', // 包含此代码块的包名
    packageRoot: '..', // 此包的根路径
    path: 'test/my_test.dart', // 代码块在此包中的位置
  );

  await expectLater(flutterLibrary.withCode(r'''
import 'package:my_package/my_widget.dart';

void main() {
  // expect-error: MISSING_REQUIRED_ARGUMENT
  MyWidget();
}
'''), compiles);
}

更多关于Flutter错误处理插件expect_error的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter错误处理插件expect_error的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,expect_error 并不是一个官方的 Dart 或 Flutter 错误处理插件。不过,假设你指的是在测试中使用的 expectLaterexpect 函数结合 throwsthrowsA 来处理错误,这是 Flutter 和 Dart 测试框架中常见的做法。

在 Flutter 测试中,我们通常使用 test 包来编写单元测试,其中包括对异常的捕获和验证。以下是一个如何使用 expectthrowsA 来处理错误的示例代码:

示例代码:使用 expectthrowsA 进行错误处理

假设我们有一个简单的函数,它可能抛出一个特定类型的异常:

// example_function.dart
void exampleFunction(bool shouldThrow) {
  if (shouldThrow) {
    throw FormatException('Invalid format');
  } else {
    print('Function executed successfully');
  }
}

现在,我们可以编写一个测试来验证这个函数在 shouldThrowtrue 时确实抛出了一个 FormatException

// example_function_test.dart
import 'package:test/test.dart';
import 'example_function.dart';

void main() {
  test('exampleFunction throws FormatException when shouldThrow is true', () {
    expect(
      () => exampleFunction(true),
      throwsA(isA<FormatException>()),
    );
  });

  test('exampleFunction does not throw when shouldThrow is false', () {
    expect(
      () => exampleFunction(false),
      returnsNormally,
    );
  });
}

解释

  1. 导入测试包:首先,我们需要导入 test/test.dart 包,这是 Dart 提供的测试框架。
  2. 定义测试函数:使用 test 函数定义测试案例。每个测试案例接收一个描述字符串和一个测试闭包。
  3. 捕获异常:使用 expect 函数来验证代码块是否抛出了预期的异常。在这里,() => exampleFunction(true) 是一个匿名函数,它调用 exampleFunction 并传入 truethrowsA(isA<FormatException>()) 是一个匹配器,它检查抛出的异常是否为 FormatException 类型。
  4. 验证正常返回:使用 returnsNormally 匹配器来验证当 shouldThrowfalse 时,函数没有抛出异常并正常返回。

运行测试

你可以使用命令行工具运行这些测试。确保你的项目根目录下有一个 pubspec.yaml 文件,并且已经添加了 test 依赖(通常这是默认包含的)。然后,运行以下命令:

flutter test

或者,如果你使用的是纯 Dart 项目(不是 Flutter 项目),可以运行:

dart test

这将执行所有定义的测试,并报告结果。

虽然 expect_error 不是一个标准的 Flutter/Dart 插件或功能,但通过上述方法,你可以有效地在 Flutter 应用中进行错误处理和测试验证。

回到顶部