4

I am attempting to Mock an Interface that has a single Task<string> method.

The same Q here, though i can't seem to get the code to work in my favor: Setup async Task callback in Moq Framework

My interface looks like this:

public interface IHttpClient
{
    Task<string> GetStringAsync(string uri);
}

I am trying to mock this up as so:

var mockHttp = new Mock<IHttpClient>();
mockHttp.Setup(m => m.GetStringAsync("aPretendUrl")).ReturnsAsync("Some sort of string");

I am finding that the result of the GetStringAsync is null

In the controller, where this instance is injected, I am calling it as so:

string responseData = await _client.GetStringAsync(url);

Also trying

string responseData = _client.GetStringAsync(url).Result;

responseData is null in all cases.

I am sure I am missing something simple. Still new with Unit tests

Can anybody point out where I am going wrong?

Update

The full unit test looks like this:

[Test]
public void Given_EController_Called_With_unknown_pedi_Returns_NotFound()
{
    // Arrange
    AppSettings settings = new AppSettings()
    {
        DataWarehouseAPI = "http://myurl.com"
    };
    Mock<IOptionsSnapshot<AppSettings>> mockSettings = new Mock<IOptionsSnapshot<AppSettings>>();
    mockSettings.Setup(m => m.Value).Returns(settings);

    var mockHttp = new Mock<IHttpClient>();
    mockHttp.Setup(m => m.GetStringAsync("aPretendUrl")).ReturnsAsync("[]");

    EntryController controller = new EntryController(mockHttp.Object, mockSettings.Object);

     // Act
    IActionResult actionResult = controller.GetByPedimento("nothing").Result;

    // Assert
    Assert.IsAssignableFrom<NotFoundObjectResult>(actionResult);
    }
Darren Wainwright
  • 30,247
  • 21
  • 76
  • 127
  • 1
    Are you sure that url value is 'aPretendUrl' when _client.GetStringAsync(url) executes? – CodeFuller Nov 07 '17 at 17:05
  • In this case it should't do anything. I am attempting to mock an implementation that returns a specific string. I don't want it to actually make a call. Maybe i am misunderstanding the Moq framework? – Darren Wainwright Nov 07 '17 at 17:06
  • what value are you sending to 'url'? – rudolf_franek Nov 07 '17 at 17:07
  • 3
    Your mock will return "Some sort of string" only if url is "aPretendUrl" and will return null for all other input urls. Could you update your question with full body of your UT? – CodeFuller Nov 07 '17 at 17:08
  • If the problem is what @CodeFuller says, you should use `mockHttp.Setup(m => m.GetStringAsync(Is.IsAny())).ReturnsAsync("Some sort of string");` – Jeppe Stig Nielsen Nov 07 '17 at 17:10
  • @CodeFuller - I will update the Q, though i just don't understand how the parameter would affect the mocked return. I'm missing a penny-drop moment.. – Darren Wainwright Nov 07 '17 at 17:22
  • I updated the Q with one of the unit tests. The string returning is different, but still returns a null within the controller, rather than the expected `"[]"` – Darren Wainwright Nov 07 '17 at 17:29
  • It's just how moq works. You could setup different return values for different input parameters or could just mock return value for any input parameter with It.IsAny(). – CodeFuller Nov 07 '17 at 17:29
  • @CodeFuller - Ok, thank you. I think i am getting it now :) – Darren Wainwright Nov 07 '17 at 17:32

1 Answers1

11

If you don't care about the 'url' in the test then you may use:

It.IsAny<string>()

result:

mockHttp.Setup(m => m.GetStringAsync(It.IsAny<string>()))
    .ReturnsAsync("Some sort of string");

If you specify 'uri' parameter in setup then you have to match it in your test to get desired return value "Some sort of string" from the method. You can specify different results for different inputs:

[TestMethod]
public async Task GetStringAsync_moqSetup()
{
    var mockHttp = new Mock<IHttpClient>();

    mockHttp.Setup(m => m.GetStringAsync(It.IsAny<string>()))
        .ReturnsAsync("Other sort of string");
    mockHttp.Setup(m => m.GetStringAsync("first"))
        .ReturnsAsync("First sort of string");

     var firstTarget = await mockHttp.Object.GetStringAsync("first");
     var differentTarget = await mockHttp.Object
         .GetStringAsync("something completely different");

    Assert.AreEqual("First sort of string", firstTarget);
    Assert.AreEqual("Other sort of string", differentTarget);
}

Review the Quickstart of the framework in order to get a better understanding of how to use it.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
rudolf_franek
  • 1,795
  • 3
  • 28
  • 41