如何对操作进行单元测试 BeginInvoke
我正在寻找一种在 Action 方法上测试 BeginInvoke 的方法,因为该方法在后台线程上运行,因此无法知道它何时实际完成或调用回调方法。我正在寻找一种方法来让我的测试等到回调被调用后再做出断言。
在下面的 Presenter 类中,您可以注意到我在后台线程上调用 PopulateView,该线程在获取数据时更新视图,并且我尝试断言视图属性已正确初始化。
我正在使用 NUnit 和 Moq。
public class Presenter
{
private IView _view;
private IService _service;
public Presenter(IView view, IService service)
{
_view = view;
_service = service;
Action action = PopulateView;
action.BeginInvoke(PopulateViewCallback, action);
}
private void PopulateViewCallback(IAsyncResult ar)
{
try
{
Action target = (Action)ar.AsyncState;
target.EndInvoke(ar);
}
catch (Exception ex)
{
Logger.Instance.LogException("Failed to initialize view", ex);
}
}
private void PopulateView()
{
Thread.Sleep(2000); // Fetch data _service.DoSomeThing()
_view.Property1 = "xyz";
}
}
I am looking for a way to test BeginInvoke on an Action method, since the method runs on a background thread there is no way of knowing when it actually completes or calls callback method. I am looking for a way to keep my test wait until the callback gets called before making assertions.
In the following Presenter class, you can notice that I am invoking PopulateView on background thread which updates the view when data is fetched and I am trying assert the view Properties are correctly initialized.
I am using NUnit and Moq.
public class Presenter
{
private IView _view;
private IService _service;
public Presenter(IView view, IService service)
{
_view = view;
_service = service;
Action action = PopulateView;
action.BeginInvoke(PopulateViewCallback, action);
}
private void PopulateViewCallback(IAsyncResult ar)
{
try
{
Action target = (Action)ar.AsyncState;
target.EndInvoke(ar);
}
catch (Exception ex)
{
Logger.Instance.LogException("Failed to initialize view", ex);
}
}
private void PopulateView()
{
Thread.Sleep(2000); // Fetch data _service.DoSomeThing()
_view.Property1 = "xyz";
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
抽象您的代码,以便您可以在测试时注入您想要的行为。
这个版本是异步的。在测试时,您可以简单地制作一个阻塞版本:
然后您的代码只需更改为:
在运行时,它是异步的。在测试时,它会阻止呼叫。
Abstract your code so that you can inject the behavior you want at testing time.
This version is asynchronous. At testing time, you can simply make a blocking version:
Then your code simply changes to this:
At runtime, it's asynchronous. At testing time, it blocks the call.
BeginInvoke()
返回一个IAsyncResult< /code>
您可以使用它来等待。
BeginInvoke()
returns anIAsyncResult
which you can use to wait.您不需要检查方法是否被调用,而是测试最终结果 - 在本例中 _view.Propert1 == "xyz"。
因为它是一个异步调用,所以您可能需要有一个循环,定期断言该值已设置,并且测试或检查必须超时,否则您的测试永远不会失败(只是卡住)。
您可能会考虑取消操作 (PopulateView) 以跳过睡眠。
You don't need to check that methods are called instead test the end result - in this case that _view.Propert1 == "xyz".
Because it's an async call you might need to have a loop that Asserts periodically that the value has been set, also a timeout on the test or the check is a must otherwise your test would never fail (just stuck).
You might consider stubbing out the action (PopulateView) in order to skip the Sleep.