首页 > 解决方案 > 如何确定是否调用了包含在 if 语句中的函数?

问题描述

我有一堂课,像这样的:

public class SomeClass: ISomeClass
{
     public async Task<ServiceResponse> PerformAction(Context context)
     {
          if(IsPartner(context))
          {
               SendTextMessageAsync(context);
          }
     }

     public bool IsPartner(Context context)
     {
          return SomeStaticHelperClass.GetIsPartner(context.PartnerId);
     }

     public async void SendTextMessageAsync(Context context)
     {
          // sends the message
     }
}

ISomeClass公开所有三种方法。

我正在使用起订量,我想编写一个测试来验证

我已经尝试了我能想到的一切。

这是我最近的尝试:

public class ReceiptServiceTests
{
    [Fact]
    public async void SendReceiptsProofsNeededNudgeAsync_ShouldCallSendTextMessageAsync_WhenSessionPartnerIdIsNotNullOrEmptyString()
    {
        var context = new Context { PartnerId = "12345" };
        var mockSomeClass = new Mock<ISomeClass>();

        // force IsPartner to return true
        mockSomeClass.Setup(m => m.IsPartner(context)).Returns(true);

        // call PerformAction which should call SendTextMessageAsync
        // because IsPartner will return true
        await mockSomeClass.Object.PerformAction(context);

        // verify SendTextMessageAsync was actually called
        mockSomeClass.Verify(m => m.SendTextMessageAsync(It.IsAny<Context>()), Times.AtLeastOnce);
    }
}

我不断收到以下错误:

(预期在模拟上至少调用一次,但从未执行过:m => m.SendTextMessageAsync)

我猜这是因为SendTextMessageAsync从未调用过。我被困在这里,我不明白如何正确调用它。

我知道这段代码中的一些(或很多)没有意义,为了简洁起见,我已经对其进行了更改。

我真正想弄清楚的是,当函数 (SendTextMessageAsync) 包装在调用另一个返回 true 的函数的if 语句中时,如何确定它是否被调用。

标签: c#moq

解决方案


正如 rgvlee 已经指出的那样,您只能模拟依赖项并验证它们的方法调用。

在您的情况下SomeStaticHelperClass,您的依赖项及其GetIsPartner可以验证的方法。

不幸的是,静态类不是模拟的好选择。如果您可以将该静态类引用替换为接口,那么您将能够轻松地模拟它。

SomeClass用途IPartnerService

public class SomeClass: ISomeClass
{
     private readonly IPartnerService partnerSvc;
     public SomeClass(IPartnerService partnerSvc)
     {
          this.partnerSvc = partnerSvc;
     }

     public async Task<ServiceResponse> PerformAction(Context context)
     {
          if(IsPartner(context))
          {
               SendTextMessageAsync(context);
          }
     }

     public bool IsPartner(Context context)
     {
          return partnerSvc.GetIsPartner(context.PartnerId);
     }

     public async void SendTextMessageAsync(Context context)
     {
          // sends the message
     }
}

SomeClass在单元测试期间使用IPartnerService模拟

public class ReceiptServiceTests
{
    [Fact]
    public async Task GivenAPartner_WhenICallPerformAction_ThenItCallsPartnerService()
    {
        //Arrange
        const string partnerId = "12345";
        var context = new Context { PartnerId = partnerId };
        var partnerSvcMock = new Mock<IPartnerService>();
        partnerSvcMock
          .Setup(svc => svc.GetIsPartner(partnerId))
          .Returns(true);

        var SUT = new SomeClass(partnerSvcMock);         

        //Act
        _ = await SUT.PerformAction(context);

        //Assert
        partnerSvcMock.Verify(svc => svc.GetIsPartner(partnerId), Times.Once);
    }
}

推荐阅读