2011-07-24 46 views
3

我正在測試一個StoreManager類的功能,該類對DataBaseConfiguration類具有依賴性。在.NET中依賴注入一個未測試類

public class StoreManager { 
    private DataBaseConfiguration dbConfig; 
    public void Store(string name) { 
    dbConfig.Store(name); 
    } 
    //other methods here 
} 

StoreManager類存儲到數據庫,我可以測試此方法是否正常工作的唯一方法是從數據庫中進行查詢。我有另一個類的生產當中做的..

public class QueryManager { 
private DataBaseConfiguration dbConfig; 
public string Query(QueryExpression expr) { 
    //query logic 
    string name = "somename"; 
    return name; 
}} 

Eventhough我所關心的測試只是我StoreManager類,它看起來對我來說,我需要使用QueryManager類來測試storedvalues。 所以我有一個基本的測試案例像這樣的......

[TestFixture] 
public class StoreManagerTest { 
[TestFixtureSetup] 
public void Setup() { 
    DatabaseConfiguration dbConfig = new DatabaseConfiguration(/*test database details*/); 
    StoreManager sm = new StoreManager(dbConfig); 
    QueryManager qm = new QueryManager(dbConfig); 
} 

[Test] 
public void TestStore_ValidStore() { 
    sm.Store("testname"); 
    string queryResult = qm.Query(new QueryExpression("query_expr")); 
    Assert.AreSame(queryResult, "testname"); 
}} 

正如你所看到的,除了ClassUnderTest(這是StoreManager),該QueryManager類也有DatabaseConfig的依賴。

我沒有很多StoreManager類中的邏輯,它只是委託DataBaseConfig類來存儲(實際上有更多類涉及存儲,它不是實際存儲數據的DataBaseConfig ..但只是爲了簡單起見,讓我們這麼說..)

我想知道是否有更好的方式來處理這個測試,而不涉及QueryManager呢? 還有一種更好的方法來將DataBaseConfiguration的依賴注入到StoreManager類中(考慮到DataBaseConfiguration類會將數據庫的連接字符串等細節存儲到..中,並且我想傳入一個測試數據庫,而不是那裏的生產數據庫連接字符串)。

回答

5

爲了在測試中獲得依賴性,最常用的方法是使用手寫存根或模擬框架(即Moq或RhinoMocks)。

此外,您必須啓用StoreManager類的用戶才能通過DataBaseConfiguration依賴關係,否則無法在不更改代碼的情況下將其存儲。您現在所做的構造函數注入是常見做法,也是一種乾淨的方法(如果您在擁有大量依賴性時使用IOC容器,則此方法變得更加方便),另請參閱here

如果我理解正確的話,你只是想測試該StoreManager實際存儲您傳遞給它的價值,你有興趣在StoreManager的行爲及其與它的依賴性DataBaseConfiguration互動 - 現在你做到這一點查詢數據存儲本身進行驗證。

鑑於我們使用RhinoMocks進行了一個簡單的例子 - 我改變的唯一方法是將DataBaseConfiguration類中的Store方法定義爲虛擬,以便RhinoMocks可以覆蓋它。

//Arrange 
string storeValue = "testname"; 
var dbConfigMock = MockRepository.GenerateMock<DataBaseConfiguration>(); 
dbConfigMock.Expect(x => x.Store(storeValue)); 
StoreManager sm = new StoreManager(dbConfigMock); 

//Act 
sm.Store(storeValue); 

//Assert 
dbConfigMock.AssertWasCalled(x => x.Store(storeValue)); 

該測試驗證Store方法被稱爲你的DataBaseConfiguration類W/O任何其他依賴 - 它測試你的StoreManager類的行爲。此測試不會觸及數據庫,也不會影響任何其他類。

編輯:

我不知道我的理解對在生產中使用的代碼嘲弄框架的關注 - 嘲諷框架只在您的測試項目,沒有提到它或任何代碼中使用生產代碼本身需要進行更改。

使用手寫存根可以「手動」執行相同的斷言:定義測試存根,存儲多少次以及存儲了什麼值Store()(同樣需要將Store方法聲明爲虛擬的,以便可以覆蓋它):

​​

現在在測試使用此測試樁,而不是 「真實」 DataBaseConfiguration

string storeValue = "testname"; 
DataBaseConfigurationTest dbConfigStub = new DataBaseConfigurationTest(); 
StoreManager sm = new StoreManager(dbConfigStub); 

sm.Store(storeValue); 

Assert.AreEqual(1, dbConfigStub.TimesCalled); 
Assert.AreEqual(storeValue, dbConfigStub.LastNameStored); 
+0

感謝您的解釋!我不確定我們是否可以在我們的生產代碼中使用Rhino Mocks(它看起來像我需要從http://builds.hibernatingrhinos.com/builds/Rhino-Mocks下載Rhino,並在我的源代碼中引用Rhino.Mocks.dll碼)。你會給出一些關於手寫存根在這種情況下的樣子嗎? – Santhosh

+0

@Santosh:更新了一個手寫存根應用於您的示例 – BrokenGlass

+0

非常感謝您的示例代碼! – Santhosh