简体   繁体   English

如何使用 Moq 在 .NET 6 的以下代码中模拟方法?

[英]How to mock methods in the below code in the .NET 6 using Moq?

Below is InvokeAsync method which need to tested.下面是需要测试的InvokeAsync方法。

    public async Task<bool> InvokeAsync(Batch batch)
    {
        var refundRequests = await this.RefundRepository.GetsAsync(batch.RefundRequests.Select(x => x.Id));

        refundRequests.RemoveAll(x => x.Status != RefundRequestStatus.Approved);
        var distributions = await DistributionRepository.GetsAsync(refundRequests.Select(x => x.Distribution.Id));

        var bundles = await this.BundleRepository.GetsAsync(distributions.Select(x => x.BundleId));

        foreach (var getRefundRequest in refundRequests)
        {
            var distribution = distributions.FirstOrDefault(x => x.Id == getRefundRequest.Distribution.Id);

            if (distribution?.BundleId != null)
            {
                var bundle = bundles.First(x => x.Id == distribution?.BundleId);

                Bundle result = await Reverse.InvokeAsync(getRefundRequest, distribution, bundle); //MOCK
            }
            getRefundRequest.Status = RefundRequestStatus.Closed;
            getRefundRequest.LastUpdatedBy = "Test User";

            bool isUpdated = await UpdateRefund.InvokeAsync(getRefundRequest); //MOCK
        }

        batch.Status = BatchStatus.Posted;
        batch.LastUpdatedBy = "Test User";
        var isSuccess = await UpdateBatch.InvokeAsync(batch); //MOCK

        return isSuccess;
    }

Unit test method单元测试方法

[Fact]
public async Task Post_Batch()
{
    foreach (var refundBatch in Factory.Batch.CreateRefundBatchesData())
    {
        var refundRequests = await this.RefundRequestRepository.GetsAsync(batch.RefundRequests.Select(x => x.Id));
        var distributions = await this.DistributionRepository.GetsAsync(refundRequests.Select(x => x.Distribution.Id));
        var bundles = await this.BundleRepository.GetsAsync(distributions.Select(x => x.BundleId));

        for (int i = 0; i < refundRequests.Count; i++)
        {
            var refundRequest = refundRequests[i];
            var bundle = bundles[i];
            var distribution = distributions[i];
            MockSetupReverse(refundRequest, distribution, bundle);
            MockSetupUpdateRefund(refundRequest);
        }

        MockSetupUpdateBatch(batch);

        //Act
        var postRefund = await UseCase.InvokeAsync(batch);

        //Assert
        postRefund.ShouldNotBeNull();
        postRefund.IsPosted.ShouldBeTrue();
    }
}

MockSetup methods模拟设置方法

private void MockSetupReverse(RefundRequest refundRequest, Distribution distribution, Bundle bundle)
{
    this.MockReverse
        .Setup(x => x.InvokeAsync(refundRequest, distribution, bundle))
        .Returns(async () => 
        {
            bundle.Status = BundleStatus.Closed;
            return await Task.Run(() => bundle); 
        });
}

private void MockSetupUpdateRefund(RefundRequest refundRequest)
{
    this.MockUpdateRefund
            .Setup(x => x.InvokeAsync(refundRequest))
            .Returns(async () =>
            {
                refundRequest.Status = RefundRequestStatus.Closed;
                refundRequest.LastUpdatedBy = Factory.RefundRequest.TestUserName;
                return await Task.Run(() => true);
            });
}

private void MockSetupUpdateBatch(Batch batch)
{
    this.MockUpdateBatch
            .Setup(x => x.InvokeAsync(batch))
            .Returns(async () =>
            {
                refundBatch.Status = BatchStatus.Posted;
                refundBatch.LastUpdatedBy = Factory.RefundRequest.TestUserName;
                return await Task.Run(() => true);
            });
}

The mocking of the UpdateBatch is working and returns true when the method is invoked. UpdateBatch的模拟正在工作,并在调用该方法时返回true But, the mocking of the Reverse and UpdateRefund returns false when the respective method is invoked.但是,当调用相应的方法时, ReverseUpdateRefund的模拟返回false Any thoughts?有什么想法吗?

Please let me know if more info is required to support the question.如果需要更多信息来支持该问题,请告诉我。

When you Setup your mocks with a specific parameter, the Returns only applies when this specific parameter is used.当您使用特定参数Setup模拟时, Returns值仅在使用此特定参数时适用。

The reason UpdateBatch works is because you're using the same reference to the same Batch in both the mock and the class under test: UpdateBatch起作用的原因是因为您在模拟和被测类中都使用了对相同Batch的相同引用:

MockSetupUpdateBatch(batch);

//Act
var postRefund = await UseCase.InvokeAsync(batch); // <---- Same "batch"

When your test code is calling RefundRequestRepository.GetsAsync you probably get different results than when the tested class calls GetsAsync , so the setup is not relevant for the calls of the tested class and probably returns the default bool value ( false ).当您的测试代码调用RefundRequestRepository.GetsAsync时,您可能会得到与测试类调用GetsAsync不同的结果,因此设置与测试类的调用无关,并且可能返回默认布尔值 ( false )。

For more information on how to mock correctly refer to this GitHub page有关如何正确模拟的更多信息,请参阅此 GitHub 页面

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM