Method Not Found when using MOQ in Unit Test - c#

I am having trouble setting up a unit test where I need to Moq the HttpClient. In my code I have a decorator for the HttpClient which follows an interface.
public class WHttpClient: IWHttpClient{
HttpClient _client = new HttpClient();
...
public async Task<HttpReponseMessage> PostAsJsonAsync<T>(string url, T content)
{
//Do Something
return await _client.PostAsJsonAsync(url, content);
}
...
}
public interface IWHttpClient{
HttpRequestHeaders DefaultRequestHeaders {get;}
Task<HttpResponseMessage> PostAsXmlAsync<T>(string url, T content);
Task<HttpResponseMessage> PostAsJsonAsync<T>(string url, T content);
Task<HttpResponseMessage> PostAsync<T>(string url, T content);
Task<HttpResponseMessage> GetAsync(string url);
Task<T> GetAsync<T>(string url);
Task<T> ReadAsAsync<T>(HttpResponseMessage response);
T Read<T>(HttpResponseMessage response);
}
[TestClass]
public class UnitTest1
{
private class WorkClass
{
private IWHttpClient _client;
public WorkClass(IWHttpClient client)
{
_client = client;
}
public void DoWork()
{
var url = "DUMMY";
var content = new ObjectToSerialize();
Task.Run(() => _client.PostAsJsonAsync(url, content));
}
}
public class ObjectToSerialize
{
}
[TestMethod]
public void TestMethod1()
{
Mock<IWHttpClient> _webClientMock = new Mock<IWHttpClient>(MockBehavior.Strict);
var url = "DUMMY";
var content = new ObjectToSerialize();
_webClientMock.Setup(x => x.PostAsJsonAsync(url, It.IsAny<ObjectToSerialize>())).Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK)));
var myClassToTest = new WorkClass(_webClientMock.Object);
myClassToTest.DoWork();
}
}
It successfully builds, but when I run the test, it gives me the exception:
System.MissingMethodException: Method not found: 'System.Threading.Tasks.Task'1 SomeNamespace.IWHttpClient.PostAsJsonAsync(System.String, !!0)'.
I've spent hours trying to figure out why I get this exception when I run the test. I have performed a clean and rebuild of my solution and yet it still appears as well as replacing the inputs in the mocksetup with:
(It.IsAny<string>(), It.IsAny<object>())
Does anyone have an idea what's wrong?
Results from running:

The following minimal example was just to try and reproduce your problem as well as demonstrate how to exercise tests like this.
[TestClass]
public class MyTestClass {
private class WorkClass {
private IWHttpClient _client;
public WorkClass(IWHttpClient client) {
_client = client;
}
public async Task DoWork() {
var url = "DUMMY";
var content = new ObjectToSerialize();
var response = await _client.PostAsJsonAsync(url, content);
}
}
public class ObjectToSerialize {
}
[TestMethod]
public async Task MyTestMethod() {
//Arrange
var expectedResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
var _webClientMock = new Mock<IWHttpClient>(MockBehavior.Strict);
_webClientMock
.Setup(_ => _.PostAsJsonAsync(It.IsAny<string>(), It.IsAny<ObjectToSerialize>()))
.ReturnsAsync(expectedResponse)
.Verifiable();
var myClassToTest = new WorkClass(_webClientMock.Object);
//Act
await myClassToTest.DoWork();
//Assert
_webClientMock.Verify();
}
}
When exercised the test behaved as expected and passed. Even when the setup was changed to
.Setup(_ => _.PostAsJsonAsync(It.IsAny<string>(), It.IsAny<object>()))
Review and compare to your current test to help identify where possible mistakes may have been made.

Related

Http response cannot be deserialized when it's created from test case

I'm trying to run this test:
[TestFixture]
public class AccountManagementViewModelTests
{
[Test, BaseAutoData]
public void OnSync_Should_AddToDatabase_MissingLists(
[Frozen] Mock<IHttpClientService> httpClientService,
[Frozen] Mock<IDataStore<AppModel.List>> dataStore,
List<ApiModel.List> lists,
AccountManagementViewModel sut)
{
// Arrange
httpClientService
.Setup(x => x.GetAsync(It.IsAny<string>()))
.ReturnsAsync(new HttpResponseMessage()
{
Content = JsonContent.Create(lists)
});
// Act
sut.SyncCommand.Execute(null);
// Assert
dataStore.Verify(
d => d.AddItemAsync(
It.Is<AppModel.List>(
x => lists.Any(y => y.Guid == x.ListId))),
Times.Exactly(3));
}
}
Problem is, when I try to deserialize the response, I get 3 empty entities
var allBackedupListsForCurrentUserRequestTask = _httpClientService.GetAsync(string.Format(ListApiEndPoints.GetListsByOwnerEmail, ApplicationUser.Current.Email));
var allBackedupListsForCurrentUserRequest = await allBackedupListsForCurrentUserRequestTask;
var allBackedupListsForCurrentUser = await JsonSerializer.DeserializeAsync<List<ApiModel.List>>(await allBackedupListsForCurrentUserRequest.Content.ReadAsStreamAsync());
If I examine the content of allBackedupListsForCurrentUserRequest.Content I can see all the data there, but none are deserialized into the allBackedupListsForCurrentUser.
The code works fine with real HttpRequests, the issue rises only during unit tests.
What am I missing here?
Other classes involved:
HttpClientService
using ListApp.Services.Interfaces;
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace ListApp.Services
{
public class HttpClientService : IHttpClientService
{
private static HttpClient _httpClient = new HttpClient();
public async Task<HttpResponseMessage> GetAsync(string requestUri)
{
return await _httpClient.GetAsync(requestUri);
}
public async Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content)
{
return await _httpClient.PutAsync(requestUri, content);
}
public async Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
{
return await _httpClient.PostAsync(requestUri, content);
}
public void SetBaseAddress(Uri baseAddress)
{
_httpClient.BaseAddress = baseAddress;
}
}
}
BaseAutoDataAttribute
using AutoFixture;
using AutoFixture.AutoMoq;
using AutoFixture.NUnit3;
using System;
namespace ListApp.UnitTests.DataTtributes
{
[AttributeUsage(AttributeTargets.Method)]
internal class BaseAutoDataAttribute : AutoDataAttribute
{
public BaseAutoDataAttribute() : base(() => CreateFixture()) { }
private static IFixture CreateFixture()
{
var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true, GenerateDelegates = true });
return fixture;
}
}
}
Turns out I'm changing the value of JsonSerializerOptions.PropertyNameCaseInsensitive to true when the app starts but not during the tests.
Setting it to true on the [OneTimeSetUp] did the trick.
((JsonSerializerOptions)typeof(JsonSerializerOptions)
.GetField("s_defaultOptions",
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.NonPublic).GetValue(null))
.PropertyNameCaseInsensitive = true;
Solution by andre-ss6.

How to close Resharper test runner after finishing integration test in xUnit Test project (.NET Core)?

i am new to integration tests. I have an xUnit project in my solution which contains one test only.
Here's the definition of my test:
[Fact]
public async Task ShouldCreateUser()
{
// Arrange
var createUserRequest = new CreateUserRequest
{
Login = "testowyLogin",
Password = "testoweHaslo",
FirstName = "testoweImie",
LastName = "testoweNazwisko",
MailAddress = "test#test.pl"
};
var serializedCreateUserRequest = SerializeObject(createUserRequest);
// Act
var response = await HttpClient.PostAsync(ApiRoutes.CreateUserAsyncRoute,
serializedCreateUserRequest);
// Assert
response
.StatusCode
.Should()
.Be(HttpStatusCode.OK);
}
And the BaseIntegrationTest class definition:
public abstract class BaseIntegrationTest
{
private const string TestDatabaseName = "TestDatabase";
protected BaseIntegrationTest()
{
var appFactory = new WebApplicationFactory<Startup>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
RemoveDatabaseContextFromServicesCollectionIfFound<EventStoreContext>(services);
RemoveDatabaseContextFromServicesCollectionIfFound<GrantContext>(services);
services
.AddDbContext<EventStoreContext>(options =>
options.UseInMemoryDatabase(TestDatabaseName))
.AddDbContext<GrantContext>(options =>
options.UseInMemoryDatabase(TestDatabaseName));
});
});
HttpClient = appFactory.CreateClient();
}
protected HttpClient HttpClient { get; }
protected static StringContent SerializeObject(object #object) =>
new StringContent(
JsonConvert.SerializeObject(#object),
Encoding.UTF8,
"application/json");
private static void RemoveDatabaseContextFromServicesCollectionIfFound<T>(IServiceCollection services)
where T : DbContext
{
var descriptor = services.SingleOrDefault(service =>
service.ServiceType == typeof(DbContextOptions<T>));
if (!(descriptor is null))
{
services
.Remove(descriptor);
}
}
}
When i run tests, it takes few seconds, and the test ends successfully. The problem is that Resharper Test Runner still runs, although i've already have collected results. what am i doing wrong here? Do i have to somehow dispose the HttpClient, after performing all tests? If so, how to achieve that? Thanks for any help.
It looks like you're actually booting the application inside the test rather than using the testhost (https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1)
public class BasicTests
: IClassFixture<WebApplicationFactory<RazorPagesProject.Startup>>
{
private readonly WebApplicationFactory<RazorPagesProject.Startup> _factory;
public BasicTests(WebApplicationFactory<RazorPagesProject.Startup> factory)
{
_factory = factory;
}
[Theory]
[InlineData("/")]
[InlineData("/Index")]
[InlineData("/About")]
[InlineData("/Privacy")]
[InlineData("/Contact")]
public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url)
{
// Arrange
var client = _factory.CreateClient();
// Act
var response = await client.GetAsync(url);
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("text/html; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
}
Notice the IClassFixture stuff.

Mocking IHttpClientFactory - xUnit C#

I was trying to build a generic HTTP service in my project (c# with .net core 2.1), and I have done it as per the below snippet HttpService.
I also started using it by calling it from my business logic class which uses this generic PostAsync method to post an HTTP call to a 3rd party with a content in body. It works perfectly.
But, when I tried to test it, I failed!
Actually when I tried debugging (testing mode), I get null response when the debugger comes to this line var result = await _httpService.PostAsync("https://test.com/api", content); in business class Processor even with fake objects and mocks, although it works normally in debugging mode without testing/mocking.
HTTP service:
public interface IHttpService
{
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
}
public class HttpService : IHttpService
{
private readonly IHttpClientFactory _httpClientFactory;
public HttpService(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(3);
var response = await httpClient.PostAsync(requestUri, content).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return response;
}
}
Business class:
public class Processor : IProcessor
{
private readonly IHttpService _httpService;
public Processor() { }
public Processor(IHttpService httpService, IAppSettings appSettings)
{
_httpService = httpService;
}
public async Task<HttpResponseMessage> PostToVendor(Order order)
{
// Building content
var json = JsonConvert.SerializeObject(order, Formatting.Indented);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// HTTP POST
var result = await _httpService.PostAsync("https://test.com/api", content); // returns null during the test without stepping into the method PostAsyn itself
return result;
}
}
Test class:
public class MyTests
{
private readonly Mock<IHttpService> _fakeHttpMessageHandler;
private readonly IProcessor _processor; // contains business logic
private readonly Fixture _fixture = new Fixture();
public FunctionTest()
{
_fakeHttpMessageHandler = new Mock<IHttpService>();
_processor = new Processor(_fakeHttpMessageHandler.Object);
}
[Fact]
public async Task Post_To_Vendor_Should_Return_Valid_Response()
{
var fakeHttpResponseMessage = new Mock<HttpResponseMessage>(MockBehavior.Loose, new object[] { HttpStatusCode.OK });
var responseModel = new ResponseModel
{
success = true,
uuid = Guid.NewGuid().ToString()
};
fakeHttpResponseMessage.Object.Content = new StringContent(JsonConvert.SerializeObject(responseModel), Encoding.UTF8, "application/json");
var fakeContent = _fixture.Build<DTO>().Create(); // DTO is the body which gonna be sent to the API
var content = new StringContent(JsonConvert.SerializeObject(fakeContent), Encoding.UTF8, "application/json");
_fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), content))
.Returns(Task.FromResult(fakeHttpResponseMessage.Object));
var res = _processor.PostToVendor(fakeContent).Result;
Assert.NotNull(res.Content);
var actual = JsonConvert.SerializeObject(responseModel);
var expected = await res.Content.ReadAsStringAsync();
Assert.Equal(expected, actual);
}
}
Your problem is in mock set up:
_fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), content))
.Returns(Task.FromResult(fakeHttpResponseMessage.Object));
Second parameter for PostAsync method expected to be content, but since StringContent is a reference type, content you setup in mock is different from content you creating in processor. If you change it to next one, it should work as you expect:
_fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), It.IsAny<StringContent>()))
.Returns(Task.FromResult(fakeHttpResponseMessage.Object));
P.S. null response to PostAsync means that method has default setup, which means that it will return default value

Mocking Fails for Azure Function (IHttpClientFactory)

I am facing issues while mocking the IHttpClientFactory Interface in Azure Function. Here is What am doing, I have trigger, once the message the received I am calling an API to update data. I am using SendAsync Method for that. While writing unit test case, I am not able to mock the client.For testing , I have tried making the get call in the constructor itself, still didn't work.
Function Class
public class UpdateDB
{
private readonly IHttpClientFactory _clientFactory;
private readonly HttpClient _client;
public UpdateDB(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
_client = clientFactory.CreateClient();
_client.GetAsync("");
}
[FunctionName("DB Update")]
public async Task Run([ServiceBusTrigger("topic", "dbupdate", Connection = "connection")]string mySbMsg, ILogger log)
{
var client = _clientFactory.CreateClient();
log.LogInformation($"C# ServiceBus topic trigger function processed message: {mySbMsg}");
DBConvert payload = JsonConvert.DeserializeObject<DBConvert>(mySbMsg);
string jsonContent = JsonConvert.SerializeObject(payload);
var httpContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, "api/DBU/data");
message.Content = httpContent;
var response = await client.SendAsync(message);
}
}
TestClass
namespace XUnitTestProject1
{
public class DelegatingHandlerStub : DelegatingHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public DelegatingHandlerStub()
{
_handlerFunc = (request, cancellationToken) => Task.FromResult(request.CreateResponse(HttpStatusCode.OK));
}
public DelegatingHandlerStub(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc)
{
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return _handlerFunc(request, cancellationToken);
}
}
public class test
{
[Fact]
public async Task Should_Return_Ok()
{
//
Mock<ILogger> _logger = new Mock<ILogger>();
var expected = "Hello World";
var mockFactory = new Mock<IHttpClientFactory>();
var configuration = new HttpConfiguration();
var clientHandlerStub = new DelegatingHandlerStub((request, cancellationToken) =>
{
request.SetConfiguration(configuration);
var response = request.CreateResponse(HttpStatusCode.Accepted);
return Task.FromResult(response);
});
var client = new HttpClient(clientHandlerStub);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
var clientTest = mockFactory.Object.CreateClient();
//Works Here, but not in the instance.
clientTest.GetAsync("");
IHttpClientFactory factory = mockFactory.Object;
var service = new UpdateDB(factory);
await service.Run("", _logger.Object);
}
}
}
I have followed the sample here. How to mock the new HttpClientFactory in .NET Core 2.1 using Moq
For mocking/intercepting HttpClient usage, I would recommend you to use mockhttp
Your test would then be:
class Test {
private readonly Mock<IHttpClientFactory> httpClientFactory;
private readonly MockHttpMessageHandler handler;
constructor(){
this.handler = new MockHttpMessageHandler();
this.httpClientFactory = new Mock<IHttpClientFactory>();
this.httpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>()))
.Returns(handler.ToHttpClient());
}
[Fact]
public async Task Test(){
// Arrange
this.handler.Expect("api/DBU/data")
.Respond(HttpStatusCode.Ok);
var sut = this.CreateSut();
// Act
await sut.Run(...);
// Assert
this.handler.VerifyNoOutstandingExpectation();
}
private UpdateDB CreateSut() => new UpdateDB(this.httpClientFactory.Object);
}
You can further configure how the HTTP request expectation should behave, but for that you should read a bit the documentation of mockhttp

How to mock RestSharp portable library in Unit Test

I would like to mockup the RestClient class for test purposes
public class DataServices : IDataServices
{
private readonly IRestClient _restClient;
public DataServices(IRestClient restClient)
{
_restClient = restClient;
}
public async Task<User> GetUserByUserName(string userName)
{
User user = null;
// create a new request
var restRequest = new RestRequest("User", Method.GET);
// create REST parameters
restRequest.AddParameter("userName", userName, ParameterType.QueryString);
// execute the REST request
var restResponse = await _restClient.Execute<User>(restRequest);
if (restResponse.StatusCode.Equals(HttpStatusCode.OK))
{
user = restResponse.Data;
}
return user;
}
}
My test class :
[TestClass]
public class DataServicesTest
{
public static IRestClient MockRestClient<T>(HttpStatusCode httpStatusCode, string json)
{
var mockIRestClient = new Mock<IRestClient>();
mockIRestClient.Setup(x => x.Execute<T>(It.IsAny<IRestRequest>()))
.Returns(new RestResponse<T>
{
Data = JsonConvert.DeserializeObject<T>(json),
StatusCode = httpStatusCode
});
return mockIRestClient.Object;
}
[TestMethod]
public async void GetUserByUserName()
{
var dataServices = new DataServices(MockRestClient<User>(HttpStatusCode.OK, "my json code"));
var user = await dataServices.GetUserByUserName("User1");
Assert.AreEqual("User1", user.Username);
}
}
But I can't instantiate the RestResponse object, I've the following error:
.Returns(new RestResponse<T>
{
Data = JsonConvert.DeserializeObject<T>(json),
StatusCode = httpStatusCode
});
Cannot access protected internal constructor 'RestResponse' here.
How can I workaround this ? I'm using the FubarCoder.RestSharp nuget package on a Xamarin portable Library.
Mock IRestResponse<T> and return that
public static IRestClient MockRestClient<T>(HttpStatusCode httpStatusCode, string json)
where T : new() {
var data = JsonConvert.DeserializeObject<T>(json)
var response = new Mock<IRestResponse<T>>();
response.Setup(_ => _.StatusCode).Returns(httpStatusCode);
response.Setup(_ => _.Data).Returns(data);
var mockIRestClient = new Mock<IRestClient>();
mockIRestClient
.Setup(x => x.Execute<T>(It.IsAny<IRestRequest>()))
.ReturnsAsync(response.Object);
return mockIRestClient.Object;
}
The test should also be updated to be async as well
[TestMethod]
public async Task GetUserByUserName() {
//Arrange
var client = MockRestClient<User>(HttpStatusCode.OK, "my json code");
var dataServices = new DataServices(client);
//Act
var user = await dataServices.GetUserByUserName("User1");
//Assert
Assert.AreEqual("User1", user.Username);
}
I didn't find any great answers so I ended up writing a helper library. I published it to NuGet - MoqRestSharp.Helpers. This project is aimed to help unit test RestSharp as it extends Mock so this helped me test my RestSharp requests and response error handling.
It uses Moq
NuGet Link
Repository Link - Examples are in the project too
Feedback is always welcome!
Complete solution
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using RestSharp;
using System.Net;
namespace RestMockTest
{
public class Tests
{
[Test]
public void Test1()
{
var client = MockRestClient<User>(HttpStatusCode.OK, "{\"Name\":\"User1\"}");
var restRequest = new RestRequest("api/item/", Method.POST);
var restResponse = client.Execute<User>(restRequest);
var user = restResponse.Data;
Assert.AreEqual("User1", user.Name);
}
public static IRestClient MockRestClient<T>(HttpStatusCode httpStatusCode, string json)
where T : new()
{
var data = JsonConvert.DeserializeObject<T>(json);
var response = new Mock<IRestResponse<T>>();
response.Setup(_ => _.StatusCode).Returns(httpStatusCode);
response.Setup(_ => _.Data).Returns(data);
var mockIRestClient = new Mock<IRestClient>();
mockIRestClient
.Setup(x => x.Execute<T>(It.IsAny<IRestRequest>()))
.Returns(response.Object);
return mockIRestClient.Object;
}
}
public class User
{
public string Name { get; set; }
}
}

Categories