简体   繁体   中英

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

Below is InvokeAsync method which need to tested.

    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. But, the mocking of the Reverse and UpdateRefund returns false when the respective method is invoked. 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.

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:

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 ).

For more information on how to mock correctly refer to this GitHub page

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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