2016-09-06 47 views
2

我正在爲我不允許修改的其他人的代碼編寫單元測試。如何在C#中不使用接口和虛擬方法來模擬一個類?

說我有:

class BadClass 
{ 
    public BadClass() 
    { 
     // the service isn't going to be running during testing 
     // it also has no interface 
     someFlag = AGloballyStoredService.getSomeFlag(); 
    } 

    public bool someFlag; 

} 

所使用的:

class AnotherBadClass 
{ 
    public AnotherBadClass(BadClass badClass) 
    { 
     someFlag = badClass.someFlag; 
    } 
    public bool someFlag; 
} 

說我想測試:

public void AnotherBadClassConstructorTest() 
{ 
    BadClass badClass = new BadClass(); 
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClass); 
    Assert.IsNotNull(anotherBadClass); 
} 

我想嘲笑BadClass,但它有沒有接口,如果服務沒有運行,它會在構造函數中失敗。

考慮到我無法修改我正在測試的代碼,有沒有一種簡單的方法可以使這項工作成爲可能?

如果涉及到它,我可以告訴他們,他們必須讓我修改現有的代碼庫或接受該模塊的10%以下的覆蓋率。

+2

您可能需要使用像[Microsoft Fakes](https://msdn.microsoft.com/en-us/library/hh549175.aspx)這樣的專業庫來截取並重寫將其重定向到的方法你的嘲笑。 –

+1

恐怕只有集成測試纔是真正的選擇,如果您無法觸摸代碼。 –

回答

4

考慮到我不能修改我的測試代碼,有沒有使這個工作 簡單的方法?

否。但是,我看到兩個,非簡單的選擇:

A)使用Microsoft Fakes通過重寫庫提供的嘲笑。您不必修改代碼。例如:你可以修改靜態DateTime.Now來回報您選擇的日期如下:

System.Fakes.ShimDateTime.NowGet = 
() => 
{ return new DateTime(fixedYear, 1, 1); }; 

B)你可以試着繼承測試類並覆蓋使用的方法/構建函數。但有兩個限制。你必須能夠用你的模擬對象實例化/交換被測試的類的實例(通過使用可以得到私有成員的反射),並且模擬的方法必須是虛擬的。在你的情況,你會創建:

class BadClassMock : BadClass 
{ 
    public BadClassMock() 
    { 
    } 

    public bool someFlag; 

    public void InitForTest() 
    { 
     someFlag = true; 
    } 
} 

,它會工作,只要你不會調用基構造函數。您可以使用討厭FormatterServices.GetUninitializedObject()招從這裏:Creating instance of type without default constructor in C# using reflection

及更高版本:

public void AnotherBadClassConstructorTest() 
{ 
    BadClassMock badClassMock = (BadClassMock)FormatterServices.GetUninitializedObject(typeof(BadClassMock)); 
    badClassMock.InitForTest(); 
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClassMock); 
    Assert.IsNotNull(anotherBadClass); 
} 

是的,這是相當大的解決方法。顯然最好的方法是說服作者修改代碼。

+0

這可以工作,但它看起來像我可能無法帶入假貨。知道Moq中是否有類似的功能? – Damien

+0

Moq適用於不同級別。 Moq允許你使用繼承,虛擬方法或接口創建模擬 - 它不能在編譯的代碼上工作,因此它不允許你模擬BadClass。有了Fakes,你只需將BadClass的編譯代碼交換到任何你想要的。您仍然可以嘗試B選項。 – piotrwest

0

實際上,您可以在不修改代碼的情況下模擬BadClass,通過使用TypeMock Isolator即使它不是虛擬或界面,也可以模擬一個類。 例如這裏是你試圖創建測試:

[TestMethod] 
public void CreateAnotherBadClass_IsNotNull() 
{ 
    var fakeBadClass = Isolate.Fake.Instance<BadClass>(); 
    var anotherBadClass = new AnotherBadClass(fakeBadClass); 

    Assert.IsNotNull(anotherBadClass); 
} 

在這個測試中我創建的BadClass假的情況下,把它作爲參數傳遞給AnotherBadClass c'tor。

+0

您應該補充一點,此功能在TypeMock Isolator中支付... – piotrwest

0

如果您不想更改接口中的代碼,您將希望使用TypeMockJustMock來模擬此操作。兩者都是付費工具,我還沒有找到一個可以做你想做的事情的免費工具。我更喜歡JustMock。對於JustMock語法看起來像這樣:

public void AnotherBadClassConstructorTest() 
{ 
    BadClassMock badClassMock = Mock.Create<BadClassMock>(); 
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClassMock); 
    Assert.IsNotNull(anotherBadClass); 
} 

如果你打算做這個有很多還是想測試是沒有考慮到單元測試舊代碼,這些工具是非常值得的成本我意見。你總是可以免費試用,試試它們。

相關問題