如何对从函数返回的流进行单元测试?
How to unit test a stream that is returned from a function?
我有以下设置:
class Resource<T> {
T? data;
String? error;
Resource._({this.data, this.error});
factory Resource.success(T? data) => Resource._(data: data);
factory Resource.error(String error) => Resource._(error: error);
factory Resource.loading() => Resource._();
}
class CategoriesRepo{
Stream<Resource<List<Category>>> getAllCategories() async* {
yield Resource.loading();
yield (Resource.error(NetworkErrors.NO_INTERNET));
}
}
test('Loading then error',
() async {
final categoriesRepo = CategoriesRepo();
expect(
categoriesRepo.getAllCategories(),
emitsInOrder([
Resource<List<Category>>.loading(),
Resource<List<Category>>.error(""),
]));
});
我收到这个错误:
test\unit-tests\screens\categories\categories_repo_test_test.dart main.<fn>.<fn>
Expected: should emit an event that <Instance of 'Resource<List<Category>>'>
Actual: <Instance of '_ControllerStream<Resource<List<Category>>>'>
Which: emitted * Instance of 'Resource<List<Category>>'
* Instance of 'Resource<List<Category>>'
x Stream closed.
如何正确测试上述流?
测试本身是有效的,但是在对象的断言和比较方面有一个小问题。基本上 Resource.loading() == Resource.loading()
是假的,所以断言失败。
为什么是假的?默认情况下,Dart 对象(除了基元)只有在 相同的实例 .
时才相等
要使您的断言和此类测试有效,您需要为您的对象实施 ==
运算符和 hashCode。您可以手动完成,但这有点低效。很多人使用包 equatable or freezed, equatable is a bit easier as it doesn't involve code generation and is recommended by bloc(基于流的状态管理)作者。
import 'package:equatable/equatable.dart';
class Resource<T> extends Equatable {
T? data;
String? error;
Resource._({this.data, this.error});
factory Resource.success(T? data) => Resource._(data: data);
factory Resource.error(String error) => Resource._(error: error);
factory Resource.loading() => Resource._();
@override
List<Object?> get props => [data, error];
}
当然你也可以只改变断言,这样它就不再使用对象的比较,而是使用谓词和匹配器,但这并不漂亮。
expect(
categoriesRepo.getAllCategories(),
emitsInOrder(
[
predicate<Resource<List<Category>>>(
(r) => r.error == null && r.data == null),
predicate<Resource<List<Category>>>(
(r) => r.error == "" && r.data == null),
],
),
);
我有以下设置:
class Resource<T> {
T? data;
String? error;
Resource._({this.data, this.error});
factory Resource.success(T? data) => Resource._(data: data);
factory Resource.error(String error) => Resource._(error: error);
factory Resource.loading() => Resource._();
}
class CategoriesRepo{
Stream<Resource<List<Category>>> getAllCategories() async* {
yield Resource.loading();
yield (Resource.error(NetworkErrors.NO_INTERNET));
}
}
test('Loading then error',
() async {
final categoriesRepo = CategoriesRepo();
expect(
categoriesRepo.getAllCategories(),
emitsInOrder([
Resource<List<Category>>.loading(),
Resource<List<Category>>.error(""),
]));
});
我收到这个错误:
test\unit-tests\screens\categories\categories_repo_test_test.dart main.<fn>.<fn>
Expected: should emit an event that <Instance of 'Resource<List<Category>>'>
Actual: <Instance of '_ControllerStream<Resource<List<Category>>>'>
Which: emitted * Instance of 'Resource<List<Category>>'
* Instance of 'Resource<List<Category>>'
x Stream closed.
如何正确测试上述流?
测试本身是有效的,但是在对象的断言和比较方面有一个小问题。基本上 Resource.loading() == Resource.loading()
是假的,所以断言失败。
为什么是假的?默认情况下,Dart 对象(除了基元)只有在 相同的实例 .
时才相等要使您的断言和此类测试有效,您需要为您的对象实施 ==
运算符和 hashCode。您可以手动完成,但这有点低效。很多人使用包 equatable or freezed, equatable is a bit easier as it doesn't involve code generation and is recommended by bloc(基于流的状态管理)作者。
import 'package:equatable/equatable.dart';
class Resource<T> extends Equatable {
T? data;
String? error;
Resource._({this.data, this.error});
factory Resource.success(T? data) => Resource._(data: data);
factory Resource.error(String error) => Resource._(error: error);
factory Resource.loading() => Resource._();
@override
List<Object?> get props => [data, error];
}
当然你也可以只改变断言,这样它就不再使用对象的比较,而是使用谓词和匹配器,但这并不漂亮。
expect(
categoriesRepo.getAllCategories(),
emitsInOrder(
[
predicate<Resource<List<Category>>>(
(r) => r.error == null && r.data == null),
predicate<Resource<List<Category>>>(
(r) => r.error == "" && r.data == null),
],
),
);