我正在编写一个单元测试用例,当第一次付款成功而第二次付款失败时,我需要回滚第一笔付款。单元测试代码如下所示:
- 成功处理第一笔付款。
- 处理第二次付款。外部系统将抛出类似的事务错误异常。解析类似的事务错误异常以获取异常 ID 并使用异常 ID 再次处理第二个事务。
- 当实际处理第二笔交易时,系统会返回"付款被拒绝故障异常"。
- 然后,系统应使第一笔付款无效。
我已经为 (1) 编写了单元测试。SO 社区如何指导如何处理第 2、3、4 部分?
[TestMethod]
public void IfTheSecondPaymentFailsThenTheFirstPaymentShouldBeVoided()
{
//Arrange
var iPaymentMock = new Mock<IPaymentMock>();
var paymentSpecificationResponse = new PreregisteredAccountSpec();
iPaymentMock.Setup(
counter => counter.ProcessPayment
(
It.IsAny<Context>(),
It.IsAny<PreregisteredAccountSpec>(),
It.IsAny<Guid>())
).
Returns(paymentSpecificationResponse);
//Act
var twoPaymentProcessor = new TwoPaymentProcessor(iPaymentMock.Object);
twoPaymentProcessor.Submit();
//assert
iPaymentMock.Verify((
counter => counter.ProcessPaymentSpecification
(
It.IsAny<Context>(),
It.IsAny<PreregisteredAccountSpec>(),
It.IsAny<Guid>()
)
), Times.Once());
}
看起来您想在模拟中使用SetupSequence
而不是Setup
。这允许您执行类似操作
iPaymentMock.SetupSequence(counter => counter.ProcessPayment
(
It.IsAny<Context>(),
It.IsAny<PreregisteredAccountSpec>(),
It.IsAny<Guid>())
)
.Returns(paymentSpecificationResponse)
.Throws(new Exception());
我可能有你想要错的具体细节,但SetupSequence
允许你在模拟上有多个回报,但调用顺序很重要。
我不太确定如何处理 2、3 和 4 的测试,但在回答标题中的一般问题时,通过在 Returns()
子句中使用 lamba 从多次调用模拟中获得不同的回报。
假设我们有以下内容
public interface IPayment
{
Result ProcessPayment();
}
public class Result
{
public Result(int id)
{
Id = id;
}
public int Id { get; }
}
我们可以让每个调用ProcessPayment()
返回不同的值,如下所示
[TestMethod]
public void DifferentResultsOnEachInvocation()
{
var results = new[] {
new Result(1),
new Result(2),
new Result(3)
};
var index = 0;
var mockPayment = new Mock<IPayment>();
mockPayment.Setup(mk => mk.ProcessPayment()).Returns(()=>results[index++]);
var res = mockPayment.Object.ProcessPayment();
Assert.AreEqual(1, res.Id);
res = mockPayment.Object.ProcessPayment();
Assert.AreEqual(2, res.Id);
res = mockPayment.Object.ProcessPayment();
Assert.AreEqual(3, res.Id);
}
如果安装程序只是返回results[index++]
则在设置时会明确,并且每次调用都会返回数组的第一个元素。通过使其成为 lamba,每次调用 ProcessPayment()
时都会对其进行评估。