私は単体テスト、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);
}
単体テストでaMarylandProduct
または aのいずれかに対して calculate cost メソッドを呼び出せるようにしたいと考えています。SimpleProduct
通常、価格と税金はデータベースから取得されますが、代わりに、データベースやサービス、またはこれらの値を提供する他のものとの結合を避けるために、これらの値がスタブ化されるようにしました。calculateCost()
要するに、ユニットテストでそのメソッドをスタブすることなく機能をテストするユニットテストを書きたいということです.2年後にはロジック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);
}
単体テストとクラスの実装に重複したコードを入れないようにしたいのは、クラスのコードが変更された場合でも、単体テストは変更されていないため合格するためです。単体テストでその変更を行うことが期待されていることは知っていますが、大量の単体テストがある場合、この種の設計を行うことは許容されますか? 単体テストと実装でコードが重複していますか?