我正在Flutter中开发一个android/ios应用程序,我选择使用redux进行状态管理。
我正在为我的 redux 操作编写单元测试,这些操作已使用 async_redux 包实现。
我遵循软件包作者为测试制定的出色指南,但我不确定如何模拟我被测试的操作中进一步操作的调度。
例如,以下LogoutAction
调度一个DeleteDatabaseAction
并等待它完成:
class LogoutAction extends ReduxAction<AppState> {
@override
Future<AppState> reduce() async {
await dispatchFuture(DeleteDatabaseAction());
return AppState.initialState();
}
}
class DeleteDatabaseAction extends ReduxAction<AppState> {
@override
FutureOr<AppState> reduce() {
throw StateError(
'Unwanted call to runtime implementation of DeleteDatabaseAction',
);
}
}
void main() {
final store = Store<AppState>(initialState: AppState(loggedIn: true));
final storeTester = StoreTester.from(store);
test('Logout action should return correct state and not throw StateError', () async {
storeTester.dispatch(LogoutAction());
TestInfo<AppState> info = await storeTester.wait(LogoutAction);
expect(info.state.loggedIn, false);
});
}
我只想测试正在测试的操作,并存根所有进一步的操作调用。
即如何在ReduxAction
上模拟/存根dispatch
和dispatchFuture
方法,以便运行时DeleteDatabaseAction
实现不运行?
到目前为止,我已经尝试了:
使用get_it注入
DeleteDatabaseAction
并在测试期间注入模拟- 我有 100+ 个操作现在需要添加到我的上下文中
- 某些操作的参数会根据调用它们的位置而变化,因此无法在应用启动时注册
子类
Store
,覆盖上述方法并在我的测试中使用子类 此处final store = Store<AppState>(initialState: AppState(loggedIn: true))
- 我将无法调度我的测试操作,因为它在async_redux测试实现中使用相同的存储
- 在这里:
storeTester.dispatch(LogoutAction());
- 创建一个单独的
Dispatcher
实现,注入此并在测试期间用模拟覆盖- 这将起作用,但这是新的框架,我可以走这条路,但现在我偏离了 asyn_redux 提供的有据可查的框架
当您提出此问题时,这不可用。但现在答案就在这里:https://pub.dev/packages/async_redux#mocking-actions-and-reducers
要模拟操作及其化简器,请首先在测试中创建MockStore
,而不是常规Store
。MockStore
有一个mocks
参数,它是一个映射,其中键是操作类型,值是模拟。例如:
var store = MockStore<AppState>(
initialState: initialState,
mocks: {
MyAction1 : ...
MyAction2 : ...
...
},
);
但是,还有其他方法:
正如您所说,使用
get_it
或其他一些依赖项注入代码将 http 客户端注入到动作缩减器中。这很好用。使用DAO。例如:
class DeleteDatabaseAction extends ReduxAction<AppState> { @override Future<AppState> reduce() { await dao.deleteDatabase(); return null; }
然后你可以模拟 DAO 本身,或者通过
get_it
注入 DAO。你也可以让道成为某种BaseAction
(延伸ReduxAction
(的吸气剂,并将其注入到那里。