2012-06-12 66 views
1

我是新來的單元測試和TDD和一般嘲笑,但我理解的一般想法。我的問題是如何嘲笑一個類,以便我可以調用實例化的方法,而不會在單元測試和實現類中出現重複的代碼?鑑於以下幾點:與微軟鼴鼠嘲笑一個簡單的課

//Simple Interface 
public interface IProduct { 
    double price { get; set; } 
    double tax { get; set; } 
    double calculateCost(); 
} 

//Simple Implementation of IProduct 
public class SimpleProduct : IProduct { 
    private double _price; 
    private double _tax; 

    public double price { 
     get { return _price; } 
     set { _price = value; } 
    } 

    public double tax { 
     get { return _tax; } 
     set { _tax = value; } 
    } 

    public double calculateCost() { 
     return _price + (_price * _tax); 
    } 
} 
//Complex implementation of IProduct 
public class MarylandProduct : IProduct { 
    private double _price; 
    private double _tax; 

    public double price { 
     get { return _price; } 
     set { _price = value; } 
    } 

    public double tax { 
     get { return _tax; } 
     set { _tax = value; } 
    } 

    public double calculateCost() { 
     if (_price <= 100) return _price + (_price * _tax); 
     else { 
      double returnValue = 100 + (100 * _tax); //use tax rate for first 100 
      returnValue += (_price - 100) + ((_price - 100) * 0.05); //use a flat rate of 0.05 for everything over 100 
      return returnValue; 
     } 
    } 
} 

我已經開始寫具有以下單元測試:

[TestMethod] 
[HostType("Moles")] 
public void molesCalculateCostforMarylandProduct() { 
    //Assign 
    MMarylandProduct marylandProduct = new MMarylandProduct(); 
    marylandProduct.priceGet =() => 1000; 
    marylandProduct.taxGet =() => 0.07; 

    const double EXPECTED = 1052; 

    //Act 
    double actual = marylandProduct.Instance.calculateCost(); 

    //Assert 
    Assert.AreEqual(EXPECTED, actual); 
} 

我希望能夠調用計算成本法無論是MarylandProduct或在SimpleProduct我單元測試。通常情況下,從數據庫中獲取價格和稅收,但是我已經做到這一點,以便將這些值存根以避免與數據庫或服務或任何其他提供這些值的任何耦合。最重要的是我想編寫一個單元測試,它將測試calculateCost()的功能,而不必在單元測試中存儲該方法,因爲我知道在兩年內MarylandProduct中的邏輯將改變。

因此,例如,一旦我有這個測試運行,我應該能夠進入並更改MarylandProduct.calculateCost()的代碼,以增加一個「奢侈稅」,即將750添加到50以上的任何價格。如果我這樣做,我知道我的單元測試將失敗,因爲預期值爲1052,現在MarylandProduct返回的結果不是預期的結果。

我只是想以這種錯誤的方式?我錯過了TDD的精神嗎? 感謝您的幫助。

編輯:(在其他嘲諷框架補充說,我都試過)

[TestMethod] 
    public void rhinoMockCalculateCostForMarylandProduct() { 
     //assign 
     IProduct marylandProduct = MockRepository.GenerateMock<IProduct>(); 
     marylandProduct.Stub(price => price.price).Return(1000); 
     marylandProduct.Stub(tax => tax.tax).Return(0.07); 

     const double EXPECTED = 1052; 

     //act 
     double actual = marylandProduct.calculateCost(); 

     //assert 
     Assert.AreEqual(EXPECTED, actual); 
    } 

    [TestMethod] 
    public void moqCalculateCostForMarylandProduct() { 
     //assign 
     var marylandProduct = new Mock<IProduct>(); 
     marylandProduct.Setup(price => price.price).Returns(1000); 
     marylandProduct.Setup(tax => tax.tax).Returns(0.07); 

     const double EXPECTED = 1052; 

     //act 
     double actual = ((MarylandProduct)marylandProduct.Object).calculateCost(); 

     //assert 
     Assert.AreEqual(EXPECTED, actual); 
    } 

我想避免將重複的代碼在單元測試,並在類的實現,因爲如果在類變化的代碼那麼單元測試仍然會通過,因爲它沒有被改變。我知道在單元測試中可以做出這樣的改變,但是如果你有單元測試的TON,可以接受這種設計嗎?在你的單元測試和實現中有重複的代碼?

+0

如果被測改變方法的行爲,因此必須測試。如果計算成本的輸出發生變化,那麼很自然地認爲你的斷言會失敗,因爲它不再準確,所以你將不得不更新你的測試。你不可能有你的蛋糕,也可以吃它 –

+1

我沒有看到任何理由不使用正常的殘骸或嘲笑,而不是使用鼴鼠? –

+0

@ jflood.net是的,但是我想避免重複代碼(單元測試中的1和實現中的1),只是因爲我在BO中更新它,所以單元測試仍然會通過,因爲代碼在單元測試中沒有改變,它仍然會通過。這是我想要避免的。 – szeliga

回答

4

好吧,你好像是誤解是一個模擬的目的。模擬用於隔離被測系統(SUT)。因此,你可以模擬SUT的依賴關係,這樣你就可以孤立地測試SUT(例如,刪除對數據庫或某種服務的依賴)。你不嘲笑你正在測試的對象,否則,你在測試什麼?

如果我正確理解你的問題,你的域模型有一個IProduct的實現(爲什麼你需要不同的產品impls是另一個問題)。

您想要測試實現的CalculateCost方法。我看不出爲什麼你需要爲此使用mock。從表面上看,產品不應該有任何依賴性,因此沒有什麼可以嘲笑的。

例如

比方說,你在你的領域有這樣的產品:

public class MyProduct : IProduct { 
    private double _price; 
    private double _tax; 

    public double Price { 
     get { return _price; } 
     set { _price = value; } 
    } 

    public double Tax { 
     get { return _tax; } 
     set { _tax = value; } 
    } 

    public double CalculateCost() { 
     return //some complex logic here. 
    } 
} 

該對象已孤立的,它沒有依賴關係,因此沒有必要嘲笑。

爲了測試它,你將簡單地直接使用它:

[TestMethod] 
public void CalculateCost() { 
    //arrange 
    var myProduct = new MyProduct(); 
    myProduct.Price = 1000; 
    myProduct.Tax= 0.07; 

    //act 
    double actualCost = myProduct.CalculateCost(); 

    //assert 
    double expectedCost = 1052; 

    Assert.AreEqual(expectedCost, actualCost); 
} 

推薦閱讀:http://www.manning.com/osherove/

+0

我相信你回答了我的問題的性質,聽起來好像我正在以這種錯誤的方式進行,我將聽取關於單元測試藝術的建議,並確保我正確理解這一點。再次感謝您的意見。 – szeliga