【问题标题】:UnitTests - Moq - How to Return() object from Moq that matches Parameter in Setup()UnitTests - 起订量 - 如何从起订量返回()对象,该对象与设置()中的参数相匹配
【发布时间】:2017-11-07 06:40:23
【问题描述】:

我对最小起订量感到困惑,我不确定这里出了什么问题。

我想测试依赖于 ILeadStorageService 的 LeadService,并且我想以这种方式配置 Moq - 返回与设置中传递的 GUID 匹配的对象。

问题出在 Moq Setup/Returns 行,因为当我将依赖对象替换为其实际实例时 - 测试通过,但完全错误。我不想只测试 LeadService,而不是依赖存储。

    public LeadService( IConfigurationDbContext configurationDbContext, 
                        ILeadStorageService leadStorageService,
                        ILeadDeliveryService deliveryService)
    {
        this.configurationDbContext = configurationDbContext;
        this.leadStorageService = leadStorageService;
        this.deliveryService = deliveryService;

    }

测试方法

        public TestLeadResponse ProcessTestLead(TestLeadRequest request)
        {
        var response = new TestLeadResponse()
        {
            Status = TestLeadStatus.Ok
        };

        try
        {
            var lead = leadStorageService.Get(request.LeadId);
            if (lead == null)
            {
                throw new LeadNotFoundException(request.LeadId);
            }

            var buyerContract =
                configurationDbContext.BuyerContracts.SingleOrDefault(bc => bc.Id == request.BuyerContractId);
            if (buyerContract == null)
            {
                throw new BuyerContractNotFoundException(request.BuyerContractId);
            }

            response.DeliveryEntry = deliveryService.DeliverLead(lead, buyerContract);
        }
        catch (LeadNotFoundException e)
        {
            response.Status = TestLeadStatus.LeadNotFound;
            response.StatusDescription = e.Message;
        }
        catch (BuyerContractNotFoundException e)
        {
            response.Status = TestLeadStatus.BuyerContractNotFound;
            response.StatusDescription = e.Message;
        }

        return response;
    }

然后在测试准备中:

    [TestInitialize]
    public void Initialize()
    {
        _leadIdStr = "2c3ac0c0-f0c2-4eb0-a55e-600ae3ada221";

        _dbcontext = new ConfigurationDbContext();
        _lead = PrepareLeadObject();
        _buyerContract = PrepareBuyerContractObject(Id : 1, BuyerContractId :  1, BuyerTag: "GAME");
        _leadDeliveryMock = new Mock<ILeadDeliveryService>();
        _leadStorageMock = new Mock<ILeadStorageService>();
        _leadStorageService = new LeadStorageService("LeadGeneration_Dev");

    }

    private Lead PrepareLeadObject()
    {
        var lead = new Lead() {CountryId = 1, Country = "NL", Id = Guid.Parse(_leadIdStr)};
        return lead;

    }

和测试本身:

    [TestMethod]
    public void LeadServiceTest_ProcessTestLeadWithWrongBuyerContractIDThrowsBuyerContractNotFoundException()
    {
        _leadDeliveryMock
            .Setup(methodCall => methodCall.DeliverLead(_lead, _buyerContract))
            .Returns<LeadDeliveryEntry>((r) => PrepareLeadDeliveryEntry());

        // here is the problem!!!!
        _leadStorageMock.Setup(mc => mc.Get(_leadId)).Returns((Lead l) => PrepareLeadObject());

        //if i change to real object - test passes
        //_service = new LeadService(_dbcontext, _leadStorageService, _leadDeliveryMock.Object);
        _service = new LeadService(_dbcontext, _leadStorageMock.Object, _leadDeliveryMock.Object);

        var response = _service.ProcessTestLead(new TestLeadRequest() { BuyerContractId = int.MaxValue, LeadId = _leadId });

        Assert.IsNotNull(response);
        Assert.AreEqual(response.Status, TestLeadStatus.BuyerContractNotFound);

    }

而不是预期的返回 - 我遇到了一个异常:

我在 _leadStorageMock.Setup().Returns() 中缺少什么?

【问题讨论】:

    标签: c# unit-testing moq mstest


    【解决方案1】:

    Returns 扩展方法接受与您正在模拟的方法具有相同参数的委托。并且这些参数将在调用模拟方法期间传递给委托。因此,您将获得传递给 mc.Get 方法的参数,而不是 Lead 对象 - 潜在客户 ID:

    _leadStorageMock.Setup(mc => mc.Get(_leadId))
          .Returns((Guid leadId) => PrepareLeadObject());
    

    在返回值时检查与访问调用参数相关的QuickStart部分。


    请注意,有很多 Returns 扩展方法接受值函数作为参数:

    Returns<T>(Func<T, TResult> valueFunction);
    Returns<T1, T2>(Func<T1, T2, TResult> valueFunction);
    Returns<T1, T2, T3>(Func<T1, T2, T3, TResult> valueFunction);
    // etc
    

    如您所见,这些值函数计算从模拟方法返回的值,但它们都接收不同数量的参数(最多 16 个)。这些参数将与您正在模拟的方法的参数完全匹配,并且它们将在调用模拟方法期间传递给valueFunction。所以如果你用两个参数模拟一些函数,那么应该使用相应的扩展:

    mock.Setup(m => m.Activate(It.IsAny<int>(), It.IsAny<bool>())
        .Returns((int i, bool b) => b ? i : 0); // Func<T1, T2, TResult>
    

    【讨论】:

    • 谢谢!这不是那么明显。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 2021-12-14
    • 1970-01-01
    • 2022-01-16
    • 2010-11-06
    • 1970-01-01
    • 2016-11-25
    相关资源
    最近更新 更多