我很难找到一个简单、灵活的模式来允许我在 ViewModel 中编写代码,这些代码在运行时会异步运行,但在测试时会同步运行。这就是我的想法——有人有什么建议吗?这是一条好的路吗?是否有更好的现有模式?
LongRunningCall 定义:
public class LongRunningCall
{
public Action ExecuteAction { get; set; }
public Action PostExecuteAction { get; set; }
public LongRunningCall(Action executeAction = null, Action postExecuteAction = null)
{
ExecuteAction = executeAction;
PostExecuteAction = postExecuteAction;
}
public void Execute(Action<Exception> onError)
{
try
{
ExecuteAction();
PostExecuteAction();
}
catch (Exception ex)
{
if (onError == null)
throw;
onError(ex);
}
}
public void ExecuteAsync(TaskScheduler scheduler, Action<Exception> onError)
{
var executeTask = Task.Factory.StartNew(ExecuteAction);
var postExecuteTask = executeTask.ContinueWith((t) =>
{
if (t.Exception != null)
throw t.Exception;
PostExecuteAction();
}, scheduler);
if (onError != null)
postExecuteTask.ContinueWith((t) => { onError(t.Exception); });
}
}
用法:
var continueCall = new LongRunningCall(continueCommand_Execute, continueCommand_PostExecute);
if (svc.IsAsyncRequired)
continueCall.ExecuteAsync(TaskScheduler.FromCurrentSynchronizationContext(), continueCommand_Error);
else
continueCall.Execute(continueCommand_Error);
唯一真正的先决条件是您需要在运行时知道是否应该使用异步/同步。当我运行单元测试时,我发送一个模拟,告诉我的代码同步运行,当应用程序实际运行时 IsAsyncRequired 默认为 true;
反馈?
最佳答案
我更愿意将关于是否同步或异步执行代码的决定封装在一个单独的类中,该类可以在接口(interface)后面抽象,如下所示:
public interface ITaskExecuter
{
void ScheduleTask(
Action executeAction,
Action postExecuteAction,
Action<Exception> onException);
}
可以在需要时注入(inject)实现ITaskExecuter
的类的实例。
您可以为测试场景和生产场景注入(inject)不同的实例。
用法变为:
taskExecuter.ScheduleTask(
continueCommand_Execute,
continueCommand_PostExecute,
continueCommand_Error);
在测试与生产的调用类中没有单独的代码路径。
您可以选择编写以下测试:
- 只需检查是否将正确的操作传递给任务执行器,或者
- 配置任务执行器以同步执行操作并 测试所需的结果,或
- 两者都做。
关于c# - 可测试异步操作的体面模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8042578/