使用最小起订量多次调用相同的方法,具有不同的回报



我正在编写一个单元测试用例,当第一次付款成功而第二次付款失败时,我需要回滚第一笔付款。单元测试代码如下所示:

  1. 成功处理第一笔付款。
  2. 处理第二次付款。外部系统将抛出类似的事务错误异常。解析类似的事务错误异常以获取异常 ID 并使用异常 ID 再次处理第二个事务。
  3. 当实际处理第二笔交易时,系统会返回"付款被拒绝故障异常"。
  4. 然后,系统应使第一笔付款无效。

我已经为 (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() 时都会对其进行评估。