dart-generate-test-mocks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTesting and Mocking Dart Applications
Dart应用的测试与模拟
Contents
目录
Structuring Code for Testability
为可测试性构建代码结构
Design Dart classes to support dependency injection. Isolate complex external dependencies (like API clients or databases) so they can be replaced with mock objects during testing.
- Inject external services (e.g., ) through class constructors.
http.Client - Represent URLs strictly as objects using
Uri.Uri.parse(string) - Utilize Dart's object-oriented features (classes, mixins) to define clear interfaces for external interactions.
设计Dart类以支持依赖注入。隔离API客户端或数据库等复杂外部依赖,以便在测试期间用模拟对象替换它们。
- 通过类构造函数注入外部服务(例如)。
http.Client - 使用将URL严格表示为
Uri.parse(string)对象。Uri - 利用Dart的面向对象特性(类、混入)定义外部交互的清晰接口。
Managing Dependencies
依赖管理
Configure the file with the necessary testing and code generation packages.
pubspec.yaml- Add runtime dependencies (e.g., ) using
package:http.dart pub add http - Add testing dependencies using .
dart pub add dev:test dev:mockito dev:build_runner - Import HTTP libraries with a prefix to avoid namespace collisions: .
import 'package:http/http.dart' as http;
在文件中配置必要的测试和代码生成包。
pubspec.yaml- 使用添加运行时依赖(例如
dart pub add http)。package:http - 使用添加测试依赖。
dart pub add dev:test dev:mockito dev:build_runner - 为HTTP库添加前缀导入以避免命名空间冲突:。
import 'package:http/http.dart' as http;
Generating Mocks
生成模拟对象
Use and to automatically generate mock classes for fixed scenarios and behavior verification.
package:mockitobuild_runner- Always use the annotation (preferable to
@GenerateNiceMocksto avoid missing stub exceptions).@GenerateMocks - Place the annotation in the test file, passing a list of objects.
MockSpec<Type>() - Import the generated file using the extension.
.mocks.dart - Execute to generate the mock files:
build_runner.dart run build_runner build
使用和自动生成用于固定场景和行为验证的模拟类。
package:mockitobuild_runner- 始终使用注解(相比
@GenerateNiceMocks更优,可避免缺失存根异常)。@GenerateMocks - 在测试文件中放置该注解,传入对象列表。
MockSpec<Type>() - 使用扩展名导入生成的文件。
.mocks.dart - 执行生成模拟文件:
build_runner。dart run build_runner build
Implementing Unit Tests
实现单元测试
Isolate the system under test using the generated mock objects. Use to structure the test suite.
package:test- Stubbing: Configure mock behavior before interacting with the system under test.
- Use for synchronous methods.
when(mock.method()).thenReturn(value) - CRITICAL: Always use for methods returning a
thenAnswer((_) async => value)orFuture. Never useStreamfor asynchronous returns.thenReturn
- Use
- Verification: Assert that the system under test interacted with the mock object correctly.
- Use to check exact invocation counts.
verify(mock.method()).called(1) - Use argument matchers like ,
any, oranyNamedfor flexible verification.captureAny
- Use
使用生成的模拟对象隔离被测系统。使用构建测试套件。
package:test- 存根配置: 在与被测系统交互前配置模拟行为。
- 对同步方法使用。
when(mock.method()).thenReturn(value) - 重点注意: 对返回或
Future的方法,务必使用Stream。绝不要对异步返回使用thenAnswer((_) async => value)。thenReturn
- 对同步方法使用
- 验证: 断言被测系统与模拟对象的交互是否正确。
- 使用检查精确调用次数。
verify(mock.method()).called(1) - 使用、
any或anyNamed等参数匹配器进行灵活验证。captureAny
- 使用
Workflow: Creating and Running Mocked Tests
工作流程:创建并运行带模拟的测试
Use the following checklist to implement and verify mocked unit tests.
使用以下清单实现并验证带模拟的单元测试。
Task Progress
任务进度
- 1. Identify the external dependency to mock (e.g., ).
http.Client - 2. Inject the dependency into the target class constructor.
- 3. Create a test file (e.g., ) and add
target_test.dart.@GenerateNiceMocks([MockSpec<Dependency>()]) - 4. Add the or
partdirective for the generatedimportfile..mocks.dart - 5. Run to generate the mock classes.
dart run build_runner build - 6. Write the test cases using and
group().test() - 7. Stub required behaviors using .
when() - 8. Execute the target method.
- 9. Verify interactions using and assert outcomes using
verify().expect() - 10. Run the test suite using .
dart test
- 1. 确定要模拟的外部依赖(例如)。
http.Client - 2. 将依赖注入目标类的构造函数。
- 3. 创建测试文件(例如)并添加
target_test.dart。@GenerateNiceMocks([MockSpec<Dependency>()]) - 4. 添加生成的文件的
.mocks.dart或part指令。import - 5. 运行生成模拟类。
dart run build_runner build - 6. 使用和
group()编写测试用例。test() - 7. 使用配置所需的存根行为。
when() - 8. 执行目标方法。
- 9. 使用验证交互,并使用
verify()断言结果。expect() - 10. 使用运行测试套件。
dart test
Feedback Loop: Test Failures
反馈循环:测试失败处理
If tests fail or encounters errors:
build_runner- Run validator: Execute or
dart test.dart run build_runner build - Review errors: Check for missing stubs, mismatched argument matchers, or syntax errors in the generated files.
- Fix:
- If a mock method throws an unexpected null error, ensure you used .
@GenerateNiceMocks - If an async stub throws an , change
ArgumentErrortothenReturn.thenAnswer - If fails, ensure the
build_runnerimport matches the file name exactly..mocks.dart
- If a mock method throws an unexpected null error, ensure you used
- Repeat until all tests pass.
如果测试失败或遇到错误:
build_runner- 运行验证器: 执行或
dart test。dart run build_runner build - 查看错误: 检查是否存在缺失的存根、不匹配的参数匹配器或生成文件中的语法错误。
- 修复:
- 如果模拟方法抛出意外的空值错误,请确保使用了。
@GenerateNiceMocks - 如果异步存根抛出,将
ArgumentError改为thenReturn。thenAnswer - 如果失败,请确保
build_runner的导入与文件名完全匹配。.mocks.dart
- 如果模拟方法抛出意外的空值错误,请确保使用了
- 重复上述步骤直到所有测试通过。
Examples
示例
High-Fidelity Mocking and Testing Example
高保真模拟与测试示例
1. System Under Test ()
lib/api_service.dartdart
import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService {
final http.Client client;
ApiService(this.client);
Future<String> fetchData(String urlString) async {
final uri = Uri.parse(urlString);
final response = await client.get(uri);
if (response.statusCode == 200) {
return jsonDecode(response.body)['data'];
} else {
throw Exception('Failed to load data');
}
}
}2. Test Implementation ()
test/api_service_test.dartdart
import 'package:test/test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:http/http.dart' as http;
import 'package:my_app/api_service.dart';
// Generate the mock class for http.Client
([MockSpec<http.Client>()])
import 'api_service_test.mocks.dart';
void main() {
group('ApiService', () {
late ApiService apiService;
late MockClient mockHttpClient;
setUp(() {
mockHttpClient = MockClient();
apiService = ApiService(mockHttpClient);
});
test('returns data if the http call completes successfully', () async {
// Arrange: Stub the async HTTP GET request using thenAnswer
when(mockHttpClient.get(any)).thenAnswer(
(_) async => http.Response('{"data": "Success"}', 200),
);
// Act
final result = await apiService.fetchData('https://api.example.com/data');
// Assert
expect(result, 'Success');
// Verify the mock was called with the correct Uri
verify(mockHttpClient.get(Uri.parse('https://api.example.com/data'))).called(1);
});
test('throws an exception if the http call completes with an error', () {
// Arrange
when(mockHttpClient.get(any)).thenAnswer(
(_) async => http.Response('Not Found', 404),
);
// Act & Assert
expect(
apiService.fetchData('https://api.example.com/data'),
throwsException,
);
});
});
}1. 被测系统()
lib/api_service.dartdart
import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService {
final http.Client client;
ApiService(this.client);
Future<String> fetchData(String urlString) async {
final uri = Uri.parse(urlString);
final response = await client.get(uri);
if (response.statusCode == 200) {
return jsonDecode(response.body)['data'];
} else {
throw Exception('Failed to load data');
}
}
}2. 测试实现()
test/api_service_test.dartdart
import 'package:test/test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:http/http.dart' as http;
import 'package:my_app/api_service.dart';
// 为http.Client生成模拟类
([MockSpec<http.Client>()])
import 'api_service_test.mocks.dart';
void main() {
group('ApiService', () {
late ApiService apiService;
late MockClient mockHttpClient;
setUp(() {
mockHttpClient = MockClient();
apiService = ApiService(mockHttpClient);
});
test('returns data if the http call completes successfully', () async {
// 准备:使用thenAnswer存根异步HTTP GET请求
when(mockHttpClient.get(any)).thenAnswer(
(_) async => http.Response('{"data": "Success"}', 200),
);
// 执行
final result = await apiService.fetchData('https://api.example.com/data');
// 断言
expect(result, 'Success');
// 验证模拟对象是否使用正确的Uri被调用
verify(mockHttpClient.get(Uri.parse('https://api.example.com/data'))).called(1);
});
test('throws an exception if the http call completes with an error', () {
// 准备
when(mockHttpClient.get(any)).thenAnswer(
(_) async => http.Response('Not Found', 404),
);
// 执行 & 断言
expect(
apiService.fetchData('https://api.example.com/data'),
throwsException,
);
});
});
}