2009-06-30 49 views
31

所以我有一個工廠類,我試圖找出單元測試應該做什麼。從這個question我可以驗證返回的接口是我期望的特定具體類型。具有具體類作爲返回類型的單元測試工廠方法

我應該檢查工廠是否返回具體類型(因爲目前沒有必要使用接口)?目前我正在做類似如下:

[Test] 
public void CreateSomeClassWithDependencies() 
{ 
    // m_factory is instantiated in the SetUp method 
    var someClass = m_factory.CreateSomeClassWithDependencies(); 

    Assert.IsNotNull(someClass); 
} 

這樣做的問題是,Assert.IsNotNull似乎有些多餘。

而且,我的工廠方法可能設立特定類的依賴,像這樣:

public SomeClass CreateSomeClassWithDependencies() 
{ 
    return new SomeClass(CreateADependency(), CreateAnotherDependency(), 
         CreateAThirdDependency()); 
} 

我想確保我的工廠方法正確設置所有這些依賴。是否沒有其他的方法來做到這一點,然後再依賴我的屬性,然後在單元測試中檢查? (我不是修改測試主題以適應測試的大愛好者)

編輯:爲了迴應Robert Harvey的問題,我使用NUnit作爲我的單元測試框架(但我不會想到它會產生太大的差異)

+0

你使用什麼測試框架? – 2009-06-30 03:18:18

+0

一些測試框架要求您的類是虛擬的,以便測試框架可以繼承它們。有些不。巨大的差異。 – 2009-06-30 04:15:10

回答

32

通常,創建可用於基於狀態的測試的公共屬性沒有任何問題。是的:它是您創建的用於啓用測試場景的代碼,但它會傷害您的API嗎?可以想象其他客戶會在以後找到相同的房產嗎?

測試專用代碼和測試驅動設計之間有一條細線。我們不應該引入沒有其他潛力的代碼來滿足測試要求,但是引入遵循普遍接受的設計原則的新代碼是相當好的。我們讓測試驅動我們的設計 - 這就是爲什麼我們把它稱爲TDD :)

添加一個或多個屬性的一類給用戶檢查這個類的一個更好的可能性是,在我看來,往往是合理的要做的事情,所以我認爲你不應該拒絕引入這些屬性。

除此之外,我第二納德的答案:)

3

我們所做的是與工廠建立依賴關係,當測試運行時,我們使用依賴性注入框架來替代模擬工廠。然後我們對這些模擬工廠設定適當的期望。

3

你可以隨時用反射檢查東西。沒有必要爲單元測試暴露一些東西。我覺得我很少需要反思,這可能是一個糟糕的設計的標誌。

看着你的示例代碼,是的,Assert not null似乎是多餘的,取決於你設計工廠的方式,有些會從工廠返回空對象而不是異常。

23

如果工廠正在返回具體的類型,並且您保證您的工廠總是返回一個具體的類型,而不是空的,那麼不,在測試中也不會有太多的價值。它確實可以確保,隨着時間的推移,這種期望不會被違反,並且不會拋出異常等情況。

這種測試方式只是確保在您未來進行更改時,您的工廠行爲在您不知情的情況下不會改變。

如果您的語言支持它,對於您的依賴關係,您可以使用反射。這並不總是最容易維護的,並且將測試與您的實施緊密結合。你必須決定是否可以接受。這種方法往往非常脆弱。

但你真的好像試圖分離哪些類被構造,從構造函數的調用方式。使用DI框架來獲得這種靈活性可能會更好。當你需要它們時,你不需要給自己多個接縫(一個接縫是一個可以改變你的程序中的行爲而不需要在那個地方進行編輯的地方)來處理。

儘管您已經提供了示例,但您可以從工廠派生出一個類。然後覆蓋/模擬CreateADependency(),CreateAnotherDependency()CreateAThirdDependency()。現在,當您撥打CreateSomeClassWithDependencies()時,您是否能夠意義是否創建了正確的依賴關係。

注意:「seam」的定義來自Michael Feather的書「有效使用遺留代碼」。它包含許多技術的例子,以便將測試性添加到未經測試的代碼中。你可能會覺得它非常有用。

+1

我喜歡這個答案,如果你不得不處理遺留的或接近傳統的(.net 1.1)代碼而沒有測試,那麼這本書就是上帝寄來的。如果你在一個單元測試以前沒有完成的團隊中,並且你有很多你想得到單元測試的brownfield代碼,那麼這本書也是非常有用的。 – ElvisLives 2011-01-19 17:51:47

0

據我瞭解,你要測試的依賴關係是否正確構建並傳遞到新的實例?

如果我不能使用像谷歌吉斯的框架,我可能會做這樣的事情(在這裏使用JMock的和Hamcrest):

@Test 
public void CreateSomeClassWithDependencies() 
{ 
    dependencyFactory = context.mock(DependencyFactory.class); 
    classAFactory = context.mock(ClassAFactory.class); 

    myDependency0 = context.mock(MyDependency0.class); 
    myDependency1 = context.mock(MyDependency1.class); 
    myDependency2 = context.mock(MyDependency2.class); 
    myClassA = context.mock(ClassA.class); 

    context.checking(new Expectations(){{ 
     oneOf(dependencyFactory).createDependency0(); will(returnValue(myDependency0)); 
     oneOf(dependencyFactory).createDependency1(); will(returnValue(myDependency1)); 
     oneOf(dependencyFactory).createDependency2(); will(returnValue(myDependency2)); 

     oneOf(classAFactory).createClassA(myDependency0, myDependency1, myDependency2); 
     will(returnValue(myClassA)); 
    }}); 

    builder = new ClassABuilder(dependencyFactory, classAFactory); 

    assertThat(builder.make(), equalTo(myClassA)); 
} 

(如果你不能嘲笑ClassA的,你可以指定一個非模擬版本myClassA使用新的)