利用Stub來打破關連性 (1)
Source: The art of unit testing with examples in .NET, Roy Osherove
http://www.amazon.com/Art-Unit-Testing-Examples-Net/dp/1933988274/ref=sr_1_1?ie=UTF8&s=books&qid=1267086529&sr=1-1
Chapter 3 Using stubs to break dependencies
在撰寫測試程式時, 遇到最大的問題是, 受測程式和其他程式有關聯. 因為這樣的關連, 會導致你要進行單元測試的困難度.
例如下面這個程式, 若是你要測試時, 必需要和file system有互動.
public bool IsValidLogFileName(string fileName) {
// read through the configuration file
// return true if configuration says extension is suported
}
大家可能覺得這沒什麼, 可是如果我們推到真實世界的例子, 它可能是要存到XML, 或是資料庫中. 如果這種狀況, 大家就會覺得很辛苦, 因為你可能要用到存取XML的library, 或者是存取資料庫的library. 不但測試程式會變得比較複雜, 測試執行時間也會比較久一點.
因此在做單元測試時, 一個很重要觀念便是如何打破這樣的關連性, 讓你可以擁有完全的控制權或自主權. 在這個章節中作者介紹的手法便是利用stub.
那什麼是stub呢? 作者的定義如下:
(1) A stub is a controllable replacement for an existing dependnency ( or calllaborator) in the system.
(2) 藉由使用stub, 你可以直接測試受測程式, 而不用處理這樣的相依性.
簡單的說, 就是要用stub來取代真正的東西. 可是接下來你會問, 哪個部份可以被取代呢? 怎樣被取代呢? 這就是單元測試藝術所在, 你必須找到正確的地方, 去增加或使用一個indirection的layer, 來測試你要處理的受測程式. 以下作者列出了一些手法, 來告訴我們如何增加這個layer.
原先受測程式的原始碼:
public class LogAnalyzer {
public bool IsValidLogFileName(string fileName) {
IExtensionManager mgr = new FileExtensionsManager();
return mgr.IsValid(fileName);
}
}
方法1.
// (1) 定義一個interface
public interface IExtensionManager {
public bool IsValid(string fileName);
}
// (2) 實作這個interface, 讓它呼叫到原先要關聯的部份
class FileExtensionManager : IExtensionManager {
// 實作真正要做的事情
public bool IsValid(string fileName) { ... }
}
// (3) 修改原先受測程式的內容
public class LogAnalyzer {
private IExtensionManager manager;
// 設定指向真的File Extension Manager
public LogAnalyzer() {
manager = new FileExtensionManager();
}
// 設定指向File Extension Manager的 stub
public LogAnalyzer(IExtensionManager mgr) {
manager = mgr;
}
public bool IsValidLogFileName(string fileName) {
// 呼叫在construction階段所設定的File Extension Manager
return manager.IsValid(fileName);
}
}
// (4) 測試程式
[TestFixture]
public class LogAnnalyzerTests {
[Test]
public void IsValidFileName_NameShorterThan6() {
// 設定stub的內容
StubExtensionManager myFakeManager =
new StubExtensionManager();
myFakeManager.ShouldExtensionBeValid = true;
// 把stub設定到受測程式中
LogAnalyzer log = new LogAnalyzer(myFakeManager);
// 進行測試
bool result = log.IsValidLogFileName( "short.ext" );
// 檢查測試結果
Assert.IsFalse( result, "File name with less than 5 chars should have failed the method." );
}
// File Extension Manager的stub
internal class StubExtensionManager : IExtensionManager {
public bool ShouldExtensionBeValid;
public bool IsValid(string fileName) {
//實作僅供測試使用的功能
return ShouldExtensionBeValid;
}
}
}
留言列表