2010-10-27 40 views
11

考慮:如何編寫「T必須是引用類型」的單元測試?

class MyClass<T> where T : class 
{ 
} 

在這種情況下,where子句是執行一個規範,MyClass的僅是一個通用的引用類型的。

理想情況下,我應該有一個單元測試來測試這個規範。然而,這個單元測試顯然是行不通的,但它說明了什麼,我試圖完成:

[Test] 
[DoesNotCompile()] 
public void T_must_be_a_reference_type() 
{ 
    var test = new MyClass<int>(); 
} 

我能做些什麼來測試由真實不允許代碼編譯執行的規範嗎?

編輯

更多信息:好了,我的理由這樣做的(哈哈)是我一直在關注一個TDD的方法,在其中您不能寫任何代碼,除非你有一個單元測試失敗。假設你有這個:

class MyClass<T> { } 

你可以寫什麼測試,除非T是一個類,否則會失敗?像default(T) == null

進一步編輯

所以在這一個「根本原因分析」後,問題是,我是靠default(T)這一類的消費是null,以含蓄的方式。我能夠將消費者代碼重構爲另一個類,並在那裏指定一個通用類型限制(限制爲class),如果有人要刪除我上面討論的類的限制,則該代碼將無法編譯。

+3

爲什麼你不是單元測試該類被命名爲'MyClass'? – SLaks 2010-10-27 15:19:29

+0

@SLaks:technically var test = new MyClass ();會測試,不是嗎? – 2010-10-27 15:40:56

+0

我認爲@SLaks使用諷刺來證明你不需要測試編譯器......這是微軟的工作。 – TheCloudlessSky 2010-10-27 15:58:50

回答

25

爲什麼你需要一個單元測試呢?你寫一個單元測試的方法如

public void Foo(string x) 

檢查它只能取字符串,而不是整數嗎?如果沒有,你認爲有什麼區別?

編輯:只是略顯異想天開:在這種情況下,規範是由聲明驗證。測試通常應該測試行爲。這就是我喜歡代碼合同的一個方面:我不需要單獨測試合同,除非他們表達了一些複雜的東西 - 在這種情況下,我會測試的複雜性,而不是「強制執行」的比特位。

編輯:爲了應對這個問題編輯:

你可以寫什麼測試將失敗,除非牛逼是類?

可能寫一樣的東西:

Type definition = typeof(MyClass<>); 
Assert.Throws<ArgumentException>(() => definition.MakeGenericType(typeof(int))); 

然而,這似乎是逆着測試的真正目的......

+0

嗯,我試圖讓我的單元測試包括被測單元的所有規格。 – 2010-10-27 15:19:21

+0

@Jon好笑,我們想到了完全相同的例子 – 2010-10-27 15:19:25

+2

@Scott Whitlock - 但簡單的說,代碼編譯**是**你的測試。 – 2010-10-27 15:21:20

9

你不應該測試編譯器是否工作。如果你在代碼中指定這個,這就足夠了。從代碼的角度來看,這與此大致相同:

[Test] 
public void Test_whether_add_works() 
{ 
    int i = 1 + 2; 

    Assert.AreEqual(3, i); 
} 
+4

'[Test] public void Running1984(){Assert.AreEqual(5,2 + 2); }' – 2010-10-27 15:25:32

+0

Hihi,Radiohead。 – 2010-10-27 15:50:27

2

您是否正在編寫正確的單元測試?它看起來像你要測試C#編譯器,但不是你的代碼。

3

這是一個很大的問題!非常贊同您的測試驅動方法。你所掙扎的實際上是兩種範式的衝突。舊的範式,程序應該被證明是正確的,使用數學而不運行它們(我們專業的祖先在數學中遺留下來的),而編程的新範例應該通過用示例用例(即測試)來證明是正確的。所以你要嘗試的是將新範式的實踐應用於舊範式的工件,這當然不會真正起作用...

更多關於類型和測試的二分法,請參閱此優秀文章作者:Chris Smith,http://web.archive.org/web/20080822101209/http://www.pphsg.org/cdsmith/types.html