新浪微博客户端围脖七开发笔记(3) 如何添加异步测试并模拟异步方法
这几天在研究如何进行异步测试, silverlight unit test framework提供了相应支持,异步在这个framework中的含义就是把一些额外的任务排队并稍后执行。 比如有一个request()方法是异步的,一般情况下呼叫这个方法之后无法直接测试返回的结果;但在测试方法TestRequest()中,呼叫request()后可以加入一些额外任务到一个队列中,在退出TestRequest()后执行这些任务。说起来有些拗口,看下图会明白些:
一般运用下面四个方法添加任务到队列中:
EnqueueTestComplete() – 添加一个TestComplete()到队列中,这个方法告知framework测试结束了。
EnqueueCallback() – 添加一个任务到队列
EnqueueConditional() – 添加一个条件判断到队列,如果为true才继续执行
EnqueueDelay() – 添加一些等待时间到队列
下图演示了如何实际使用:
下面回到项目中,看看具体如何做:
1.添加一个MockSinaService:
public class MockSinaService : ISinaService
{
public List<Status> StatusList{get;set;}
public void GetStatuses(System.Action<IEnumerable<Status>> onGetStatusesCompleted = null, System.Action<System.Exception> onError = null, System.Action onFinally = null)
{
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(2);
timer.Tick += delegate(object sender, EventArgs e)
{
Status testStatus =
new Status
{
Text = "this is test status",
CreatedAt = DateTime.Now
};
onGetStatusesCompleted(new List<Status>() { testStatus });
timer.Stop();
};
timer.Start();
}
}
2. 添加一个公共属性SinaService到MainPageViewModel中,这样测试项目可以把它指向mock类
public ISinaService SinaService
{
get
{
if (_sinaService == null)
{
_sinaService = new SinaService();
}
return _sinaService;
}
set
{
if (value != _sinaService)
{
_sinaService = value;
}
}
}
public void RefreshHomeList()
{
Trace.DetailMsg("RefreshHomeList");
IsHomeRefreshing = true;
SinaService.GetStatuses(
delegate(IEnumerable<Status> statuses)
{
IsHomeRefreshing = false;
foreach (Status status in statuses)
{
HomeList.Add(status);
}
},
delegate(Exception exception)
{
IsHomeRefreshing = false;
});
}
[TestInitialize]
public void Initialize()
{
_mainViewModel = new MainPageViewModel();
_mockSinaService = new MockSinaService();
_mainViewModel.SinaService = _mockSinaService;
}
[TestMethod]
[Asynchronous]
public void Refresh_HomeList_Success()
{
bool isHomeListRefreshed = false;
_mainViewModel.HomeList.CollectionChanged +=
(s, e) =>
{
isHomeListRefreshed = true;
Assert.AreEqual(NotifyCollectionChangedAction.Add, e.Action);
Assert.AreEqual(1, e.NewItems.Count, "only should be +1 item");
};
_mainViewModel.RefreshHomeList();
EnqueueConditional(() => isHomeListRefreshed);
EnqueueCallback(() => Assert.AreEqual(_mainViewModel.HomeList.Count, 1, "Expected non-empty products list."));
EnqueueTestComplete();
注意这里的Asynchronous关键字,而且要让MainPageViewModelTests这个类继承SilverlightTest。
最后测试结果如下:
References:
1. silverlight2-unit-testing by jeff wilcox
2. Asynchronous test support – Silverlight unit test framework and the UI thread by jeff wilcox
3. Silverlight Unit Testing, RhinoMocks, Unity and Resharper by Justin Angel