gpt4 book ai didi

c# - 使用 Microsoft Moles 模拟一个简单的类

转载 作者:太空宇宙 更新时间:2023-11-03 21:59:08 24 4
gpt4 key购买 nike

我对单元测试和 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);
}

我希望能够在单元测试中为 MarylandProductSimpleProduct 调用计算成本方法。通常从数据库中获取价格和税金,但我这样做是为了让这些值 stub ,以避免与数据库或服务或提供这些值的任何其他东西发生任何耦合。归根结底,我想编写一个单元测试来测试 calculateCost() 的功能,而不必在单元测试中 stub 该方法,因为我知道在 2 年内逻辑MarylandProduct 将会改变。

因此,例如,一旦我运行了这个测试,我就应​​该能够进入并更改 MarylandProduct.calculateCost() 的代码以添加“奢侈税”,即在任何价格之上加 50比如 750。如果我这样做,我知道我的单元测试将失败,因为预期值为 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);
}

我想避免在单元测试和类的实现中放置重复的代码,因为如果类中的代码发生变化,那么单元测试仍然会通过,因为它没有被改变。我知道预计会在单元测试中进行更改,但是当您进行大量单元测试时,是否可以接受这种设计?在您的单元测试和实现中有重复的代码?

最佳答案

好的,您似乎误解了 Mock 的目的。模拟用于隔离被测系统 (SUT)。因此,您可以模拟 SUT 的依赖项,以便您可以单独测试 SUT(例如,删除对数据库或某些服务的依赖项)。你不要模拟你正在测试的对象,否则,你在测试什么?

如果我正确理解你的问题,你的领域模型有一个 IProduct 的实现(为什么你需要一个产品的不同 impls 是另一个问题)。

您想测试该实现的 CalculateCost 方法。我看不出你为什么需要为此使用模拟。从表面上看,Product 不应该有任何依赖关系,因此没有什么可模拟的。

例如

假设您的域中有此产品:

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/

关于c# - 使用 Microsoft Moles 模拟一个简单的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10998107/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com