user2661305
user2661305

Reputation: 381

Mock object is null in unit test

I'm writing a unit test and i have 1 mock object that will return a dynamic type which has JSON in it. The call is async and looks to be fine, however when i run the code and step into class im testing, the mock is null (m.GetResults) and the return data i set isnt shown.

Im new to using Moq and not sure if I've done something wrong. Can anyone spot any issue for why it would be null?

public async Task GetPaymentDetailSummaryTestAsync(){                        

    Task<dynamic> json = GetSampleJsonAsync();

    var mock = new Mock<ICallProcedure>();
    mock.Setup(m => m.GetResults("dbo.GetPaymentDetailSummary", 
                                 new { ID = 600002, Year = 2018})) 
                                .ReturnsAsync(json);            

    var payments = new Payments(mock.Object);
    var result = await payments.GetPaymentDetailSummaryAsync(2018, 600002);
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, typeof(List<PaymentSummary>));
    Assert.AreEqual(1, result.Count);
}

public async Task<dynamic> GetSampleJsonAsync(){            
    return await Task.FromResult(JsonConvert.SerializeObject("[{\"PaymentNumber\":1,\"Payment\":1200.00}]")); 
}

Payments class under test

public class Payments : IPayments
{
    private ICallProcedure callProc;

    public Payments(ICallProcedure CallProc)
    {
        callProc = CallProc;
    }

    public async Task<List<PaymentSummary>> GetPaymentDetailSummaryAsync(int year, int iD)
    {
        var getPaymentDetailSummary = await callProc.GetResults("dbo.GetPayment", new { ID = id, Year = year });
        List<PaymentSummary> paymentDetailSummary = null;
        paymentDetailSummary = JsonConvert.DeserializeObject<List<PaymentSummary>>(getPaymentDetailSummary);

        return paymentDetailSummary;
    }
}

Upvotes: 3

Views: 6897

Answers (1)

Nkosi
Nkosi

Reputation: 247088

You have already figured out that the setup of the mock was not matching the actual behavior to the expected behavior and that using the It.IsAny<T>() was the solution for that problem like

mock.Setup(_ => _.GetResults(It.IsAny<string>(), It.IsAny<object>())) 
    .ReturnsAsync(json); 

The resulting problem, based on the class under test and the set up of the mock is that it appears you are double serializing the expected JSON result. You manually create a JSON string and then serialize that again.

Consider refactoring the test to something a little simpler that generates the JSON using an actual object instead of try to craft it manually. The same object can be used for making assertions as well.

public async Task GetPaymentDetailSummaryTestAsync(){                        
    //Arrange
    List<PaymentSummary> expected = new List<PaymentSummary> {
        new PaymentSummary {
            PaymentNumber = 1,
            Payment = 1200.00
        }
    };
    var json = JsonConvert.SerializeObject(expected);

    var mock = new Mock<ICallProcedure>();
    mock.Setup(_ => _.GetResults(It.IsAny<string>(), It.IsAny<object>())) 
        .ReturnsAsync(json);            

    var payments = new Payments(mock.Object);

    //Act
    var actual = await payments.GetPaymentDetailSummaryAsync(2018, 600002);

    //Assert
    Assert.IsNotNull(actual);
    Assert.IsInstanceOfType(actual, typeof(List<PaymentSummary>));
    Assert.AreEqual(1, actual.Count);
    CollectionAssert.AreEquivalent(expected, actual);
}

Upvotes: 1

Related Questions