新浪微博客户端围脖七开发笔记(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();
}
}
这个类是为了模拟SinaService,减少MainPageViewModel对它的依赖。因为实际中SinaService会调用webclient异步取得数据,但MainPageViewModel其实并不关心数据是怎么来的,添加这个mock会方便单元测试。注意在实现中使用定时器来模拟webclient的异步行为。

2. 添加一个公共属性SinaService到MainPageViewModel中,这样测试项目可以把它指向mock类

代码
   
     
public ISinaService SinaService
{
get
{
if (_sinaService == null )
{
_sinaService
= new SinaService();
}
return _sinaService;
}
set
{
if (value != _sinaService)
{
_sinaService
= value;
}
}
}
3. 添加RefreshHomeList()方法到MainPageViewModel中

代码
   
     
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 ;
});
}
4. 修改TestInitialize如下,植入mock类

代码
   
     
[TestInitialize]
public void Initialize()
{
_mainViewModel
= new MainPageViewModel();
_mockSinaService
= new MockSinaService();
_mainViewModel.SinaService
= _mockSinaService;
}
5. 添加测试方法:

代码
   
     
[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。

最后测试结果如下:

新浪微博客户端围脖七开发笔记(3) 如何添加异步测试并模拟异步方法

 

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

 

你可能感兴趣的:(新浪微博)