关于单元测试的一点小结
职责分离(一个函数尽量只做一件事件,一个单元测试只测一件事件)
/// <summary> /// 发布事件 /// </summary> /// <param name="evt"></param> public void Publish(IEvent evt) { _eventQueue.Enqueue(evt); loop(); } /// <summary> /// 事件循环 /// </summary> private void loop() { if (!inEventLoop()) return; if (_eventQueue.Count == 0) return; Task.Factory.StartNew(() => { IEvent _evt; while (_eventQueue.TryDequeue(out _evt)) {} exitEventLoop();
});
}
Publish:发布消息
Loop:事件循环以及分发消息。
我们如何对着两个功能进行测试呢?首先测试发布消息,分析代码发现Publish不仅发布消息,还包含了事件循环 ,怎么办?答案很简单,想测试什么就测试什么,将发布消息的代码单独提取为一个函数publish,只需要测试这个publish函数即可。修改之后的代码如下:
public void Publish(IEvent evt) { publish(evt); loop(); } /// <summary> /// 发布事件 /// </summary> /// <param name="evt"></param> private void publish(IEvent evt) { } /// <summary> /// 事件循环 /// </summary> private void loop() { }
由此引出了TDD的概念,1先编写测试代码(即发布消息的测试代码),2再编写满足测试的代码(让刚才的测试通过),3再进行小步重构,1-2-3不断迭代。
如何测试模型内的不想被外部调用的函数?如上代码中的publish()和loop()函数,因为是private,没有访问权限。
将函数的private改为protected,编写Fake类(继承自需要测试的类型),由DispatcherFake类代替Dispatcher类进行测试
public void Publish(IEvent evt) { publish(evt); loop(); } /// <summary> /// 发布事件 /// </summary> /// <param name="evt"></param> protected void publish(IEvent evt) {} /// <summary> /// 事件循环 /// </summary> protected void loop() {}
class DispatcherFake : Dispatcher { public void publish(IEvent evt){
base.publish(evt);
}
public void loop() {
base.loop();
} }