我对单元测试和 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调用计算成本方法。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);
}
我想避免在单元测试和类的实现中放置重复的代码,因为如果类中的代码发生更改,那么单元测试仍然会通过,因为它没有被更改。我知道预计会在单元测试中做出这种改变,但是当你有大量的单元测试时,这种设计是否可以接受?在你的单元测试和你的实现中有重复的代码?