如何验证 'this' 服务的调用方法数

How to verify number of calls method of 'this' service

我正在使用带最小起订量的 NUnit 框架进行测试。我对 veryfing 有多少次这个 class 的私有方法被调用的问题。要使用模拟对象执行此操作,使用 Times 类型的参数调用 Verify() 就足够了,但我的方法是此 class 的一部分。我试图模拟当前服务 (SUT),但这可能不是最好的主意,而且无法正常工作。

苏特:

public object Post(Operations.Campaign.Merge request)
{
    List<CampaignIdWithNumberOfAds> campaignList = new List<CampaignIdWithNumberOfAds>();

        for (int i = 0; i < request.CampaignIdsToMerge.Count; i++)
        {
            if (this.CampaignRepository.Exist(request.CampaignIdsToMerge[i]))
            {
                campaignList.Add(new CampaignIdWithNumberOfAds()
                {
                    CampaignId = request.CampaignIdsToMerge[i],
                    NumberOfAdvertisement = this.CampaignRepository.GetNumberOfAdvertisementsInCampaign(request.CampaignIdsToMerge[i])
                });
            }
        }

        if (campaignList.Count > 1)
        {
            campaignList = campaignList.OrderByDescending(p => (p == null) ? -1 : p.NumberOfAdvertisement).ToList();
            List<CampaignIdWithNumberOfAds> campaignsToMerge = campaignList.Skip(1).ToList();
            CampaignIdWithNumberOfAds chosenCampaign = campaignList.FirstOrDefault<CampaignIdWithNumberOfAds>();

            uint chosenCampaignId = chosenCampaign.CampaignId;

            foreach (var campaignToMerge in campaignsToMerge)
            {
                this.MergeCampaigns(chosenCampaignId, campaignToMerge.CampaignId);
            }
        }

        return true;
    }

测试:

    [Test]
    public void MergeCampaignsPost_ValidMergeCampaignsRequest_ExecuteMergeCampaignsMethodAppropriateNumberOfTimes() 
    {
        // Arrange
        var mockCampaignService = new Mock<Toucan.Api.Services.CampaignService>();
        var request = Mother.GetValidMergeCampaignsRequest_WithDifferentNumbersOfAdvertisement();
        mockCampaignService.Setup(x => x.MergeCampaigns(It.IsAny<uint>(), It.IsAny<uint>()));

        // Act
        var response = this.Service.Post(request);

        // Assert
        mockCampaignService.Verify(x => x.MergeCampaigns(It.IsAny<uint>(), It.IsAny<uint>()), Times.Exactly(request.CampaignIdsToMerge.Count - 1));
    }

恐怕我不会在这里给你一个解决方案,虽然我宁愿建议你一些指导。单元测试有很多不同的策略,不同的人会提出不同的解决方案。基本上在我看来,您可以改变测试代码的方式(您可能同意或不同意这些,但请将它们考虑在内)。


  • 单元测试应该独立于实现

听起来很容易,但很难坚持这种方法。私有方法是您解决问题的实现。为自己的代码编写单元测试的开发人员的典型陷阱是您知道您的代码如何工作并将其反映在单元测试中。如果实现发生变化,但 public 方法仍会履行请求的合同怎么办?您几乎不想直接使用私有方法进行单元测试。这与以下有关...

  • 测试应该检查方法的输出结果

这基本上意味着如果不需要的话,不要检查某件事执行了多少次。我不确定你的 MergeCampaigns 方法在做什么,但如果你检查操作的结果而不是它执行了多少次会更好。

  • 不要过度进行单元测试 - 保持其可维护性

尝试用尽可能简单和独立的测试来测试您可以想象的每个功能场景。不要太深入地检查是否有东西被调用。否则,您将在开始时获得 100% 的覆盖率,但每次更改服务中的内容时您都会诅咒,因为这将使您的一半测试失败(假设该服务仍在执行其工作,但方式不同于开头设计的)。因此,您将花时间重写单元测试,而这些单元测试实际上不会给您创建防弹解决方案带来任何好处。


开始编写单元测试并保持覆盖率绿色非常容易,如果您想编写良好的单元测试就开始变得非常棘手。有很多宝贵的资源帮助解决这个问题。祝你好运!