如何使用模拟进行此集成测试单元测试?

时间:2016-10-20 06:46:27

标签: c# unit-testing

我是嘲笑的新手。我正在进行集成测试,我想将其更改为单元测试。我知道我必须模拟balancePositiveCalculator,因为它是与classUnderTest合作的依赖,但我不知道如何在这里模拟,所以我只测试classUnderTest。我是否必须创建balancePositiveCalculator的模拟和设置参数以及canned返回,然后使用模拟对象方法来计算cost.FeesAndInterest?我正在使用moq。

[TestMethod]
public void Calculate_VirtualSaving_PositiveSaving()
{
    var balance = 100M;
    var monthlyRepayment = 20M;
    var currentInterestRate = 18.9M;
    var savingsExpected = 24M;

    var fakeCreditCard = new CreditCardGold { Money = 15 };

    var currentFees = _classUnderTest.Calculate(balance, currentInterestRate, monthlyRepayment, 0M, 1);
    var balancePositiveCalculator = new BalancePositiveCalculator(_classUnderTest);
    var costs = balancePositiveCalculator.Calculate(fakeCreditCard, balance, monthlyRepayment);

    var savingsActual = currentFees.InterestPaid - costs.FeesAndInterest;

    savingsActual.ShouldBeInRange(savingsExpected - 1M, savingsExpected + 1M);
}

编辑(我试过这个)。这是正确的方法:

var fakeCalculatorResult = new CalculatorResult
{
    FeesAndInterest = 12
};

var mockBalancePositiveCalculator = new Mock<IBalancePositiveCalculator>();
mockBalancePositiveCalculator
    .Setup(x => x.Calculate(It.IsAny<CreditCardGold>(), It.IsAny<decimal>(), It.IsAny<decimal>()))
    .Returns(fakeCalculatorResult);

// act
var currentCreditCardCost = _classUnderTest.Calculate(balance, currentInterestRate, monthlyRepayment, 0M, 1);
var costs = mockBalancePositiveCalculator .Object.Calculate(It.IsAny<CreditCardGold>(), It.IsAny<decimal>(), It.IsAny<decimal>());

var savingsActual = currentCreditCardCost.InterestPaid - costs.FeesAndInterest;

// assert      
savingsActual.ShouldBeInRange(savingsExpected - 5M, savingsExpected + 5M);

2 个答案:

答案 0 :(得分:1)

Yes I agree with @Lee Campbell - you have your dependencies back to front. What you want to do is mock any dependencies in your class and then inject them in. That's why IOC containers are so popular when it comes to writing unit testable code. Your implementation of "_classUnderTest" has no dependencies and therefore can be unit tested on it's own. However "BalancePositiveCalculator" has a dependency on the "_classUnderTest" and that's what you want to mock and inject into "BalancePositiveCalculator".

The test would then look something like the following:

    [TestMethod]
    public void BalancePositiveCalculator()
    {
        var balance = 100M;
        var monthlyRepayment = 20M;
        var currentInterestRate = 18.9M;
        var savingsExpected = 24M;

        var fakeCreditCard = new CreditCardGold { Money = 15 };

        var classUnderTestMock = new Mock<IClassUnderTest>();
        classUnderTestMock.Setup(
            test =>
                test.Calculate(It.IsAny<decimal>(), 
                    It.IsAny<decimal>(), 
                    It.IsAny<decimal>(), 
                    It.IsAny<decimal>(),
                    It.IsAny<decimal>()))
            .Returns(new ClassUnderTest());

        classUnderTestMock.Setup(test => test.InterestPaid).Returns(balance);

        var balancePositiveCalculator = new BalancePositiveCalculator(classUnderTestMock.Object);
        var costs = balancePositiveCalculator.Calculate(fakeCreditCard, balance, monthlyRepayment);

        var savingsActual = classUnderTestMock.Object.InterestPaid - costs.FeesAndInterest;

        savingsActual.ShouldBeInRange(savingsExpected - 1M, savingsExpected + 1M);

    }

Which would also mean that you would obviously have an interface like the following:

public interface IClassUnderTest
{
    ClassUnderTest Calculate(decimal balance, 
        decimal currentInterestRate, 
        decimal monthlyRepayment, 
        decimal num1, 
        decimal num2);

    decimal InterestPaid { get; }
}

答案 1 :(得分:0)

由于您使用BalancePositiveCalculator所做的所有操作都会创建一个从另一个金额中扣除的金额,因此您可以完全省略该金额。实际上,您只测试_classUnderTest.Calculate,更确切地说是其返回值的InterestPaid属性。

我更愿意为返回值的其他属性添加一些Assert

对于BalancePositiveCalculator.Calculate方法,在那里添加一些测试。