Unit test的名稱,就是單元測試,什麼是單元呢?一個一個小個體就可以視為單位。這樣的小個體有什麼好處?除了可以鎖定問題的所在(最主要的功能,debug最怕的是不知道bug在哪邊 QQ),也可以讓測試可以更容易的使用我們可以控制的「變數」。
為什麼呢?因為個體小,我們很容易把它包起來,就好像小時候堆的沙堡,沙堡小小的,做個護城河很容易,但是現實的城堡,光是用挖土機挖就要幾天幾夜...
Stub(樁)是一個減少外部依賴的一個方法,藉由interface
(接口)的轉移,使原本依賴於外在參數變成某個虛擬的參數。就好像我們的範例,原本是要從外部取得檔案,並擷取它的名稱,這樣一來一往,花費極大的時間,更別說還要實作出這些功能。所以就需要把所有東西進行模擬化。這樣有點像是訓練飛行員的方式,不可能一下子就要他上飛機坐在駕駛艙內。會先去在模擬機器上,模擬各種飛行情況,如晴天、雨天,再根據給予的情況進行飛行操作。所以這種模擬的情況可以視為一個stub的運用。
在程式裡面,我們要做一個「模擬的駕駛艙」,裡面包圍著模擬的場景,而我們在裡面操作;所以我們要把程式碼改寫成被各種「interface」包圍著,而這些interface
可以輕易的被轉換成各種狀況。我們不必管要如何接外面的資料,甚至駕駛艙外面的天氣怎樣,我們都不用知道,只要interface
給我們天氣情境,我們根據這樣的情境反應。
至於怎麼做呢?
首先改寫LogAnalyer(新的範例寫在LearningUT
的「Day10_LogAnalyer
」)
先製作一個interface
,也就是名為IEtensionManager的interface
,並且幫這個interface
實體化一個參數。這個參數manager帶著原本interface
的功能,也就是測試「是否為log」檔的功能。
接著我們測試的對象(arrange)就是Day10_LogAnalyzer,增加建構子,讓一開始就建立manager。然後撰寫功能IsValidLogFileName()
,讓它檢測帶入的檔名是否符合規則!
class Day10_LogAnalyzer
{
private IExtensionManager manager;
public Day10_LogAnalyzer(IExtensionManager mgr)
{
manager = mgr;
}
public bool IsValidLogFileName(string fileName)
{
return manager.IsValid(fileName);
}
}
//interface: define an adapter.
public interface IExtensionManager
{
bool IsValid(string fileName);
}
主要功能寫完了,接著是測試功能。
而測試的寫在「Day10_LogAnalyerTest
」。
首先從上一段的interface
在這邊被實現,名稱為 FakeExtensionManager,裡面包含了一個新參數WillBevalid
,這邊可以管理我們要傳的值是true
還是false
。這就是我們控管的駕駛艙天氣(Stub)。
在測試的執行方法中IsValidFileName_NameSupportedExtension_ReturnsTrue()
,呼叫了我們接口,並且設定回傳值為true
。這就是我們準備回傳的stub。
接著在初始化Day10_LogAnalyzer
,也把stub帶入,帶入後執行測試、檢查檔案名稱、判斷是否為true
。
[TestFixture]
public class Day10_LogAnalyzer_Test
{
[Test]
public void IsValidFileName_NameSupportedExtension_ReturnsTrue()
{
//func: put data to stub.
FakeExtensionManager myFakeManager = new FakeExtensionManager();
myFakeManager.WillBeValid = true;
Day10_LogAnalyzer log = new Day10_LogAnalyzer(myFakeManager);
bool result = log.IsValidLogFileName("test.TEST");
Assert.True(result);
}
internal class FakeExtensionManager : IExtensionManager
{
public bool WillBeValid = false;
public bool IsValid(string filename)
{
return WillBeValid;
}
}
}
這樣簡單的接口應用就產生了,我們只要動到FakeExtensionManager
,就可以簡單的修改資料,決定回傳值為何。
接著就是比對(assert)看是否正常。
後記:
鬧了烏龍,以為自己的程式莫名的消失了,害我很緊張,想說這篇打到一半要重打了。
把虛擬機打開,赫然發現...原來我的git只有commit,沒有push到Github上,一直以為丟上去了(暈倒)