Mocking IRestResponse does not work no matter what i do, tried different ways to setup expected StatusCode
to test against MethodUnderTest. I got always 0 instead what should be from the mocked object.
Nugets involved
XUnit: 2.4.1
RestSharp: 106.15.0
AutoFixture: 4.17
Mocking IRestResponse<T>
[Theory]
[AutoMockedWithInjectionData]
public void ThrowExceptionWhenResponseNot200([Frozen] IOptions<Configuration> options,
[Frozen] Mock<RestSharp.IRestClient> restClientStub,
ExternalApiService sut)
{
Mock<IRestResponse<CreateResponse>> responseStub = new();
responseStub.Setup(stub => stub.StatusCode).Returns(HttpStatusCode.NotFound);
restClientStub.Setup(stub => stub.Execute<CreateResponse>(It.IsAny<IRestRequest>()))
.Returns(responseStub.Object);
Assert.Throws<InvokeExternalServiceException>(() => sut.Execute(new RequestCreateAttachment{}));
}
Mocking IRestResponse
[Theory]
[AutoMockedWithInjectionData]
public void ThrowExceptionWhenResponseNot200([Frozen] IOptions<Configuration> options,
[Frozen] Mock<RestSharp.IRestClient> restClientStub,
ExternalApiService sut)
{
Mock<IRestResponse> responseStub = new();
responseStub.Setup(stub => stub.StatusCode).Returns(HttpStatusCode.NotFound);
restClientStub.Setup(stub => stub.MethodUnderTest(It.IsAny<IRestRequest>()))
.Returns(responseStub.Object);
Assert.Throws<InvokeExternalServiceException>(() => sut.Execute(new RequestCreate{}));
}
Returning concrete object
[Theory]
[AutoMockedWithInjectionData]
public void ThrowExceptionWhenResponseNot200([Frozen] IOptions<Configuration> options,
[Frozen] Mock<RestSharp.IRestClient> restClientStub,
ExternalApiService sut)
{
restClientStub.Setup(stub => stub.Execute<CreateResponse>(It.IsAny<IRestRequest>()))
.Returns(new RestResponse<CreateResponse>()
{
StatusCode = HttpStatusCode.NotFound
});
Assert.Throws<InvokeExternalServiceException>(() => sut.Execute(new RequestCreateAttachment{}));
}
postResponse.StatusCode is always 0
public void MethodUnderTest(RequestCreate requestCreate)
{
IRestRequest postRequest = new RestRequest
{
Method = Method.POST,
Resource = "fakepath",
};
postRequest.AddHeader("Content-Type", "application/json");
IRestResponse<CreateResponse> postResponse = restClient.Post<CreateResponse>(postRequest);
if(postResponse.StatusCode != HttpStatusCode.OK)
{
throw new InvokeExternalServiceException("...");
}
}
best regards
Related
I'm unit testing the following service and the issue is that I'm able to test only the happy path but not the unhappy path. So how do I test them? TestScheduler? http://introtorx.com/Content/v1.0.10621.0/16_TestingRx.html
These lines are left untested:
.Catch<string, TimeoutExceptiocn>(_ => Observable.Return("Timeout"))
.Catch<string, Exception>(ex => Observable.Return(ex.Message))
public interface IProductService
{
Task<string> GetAsync();
}
public sealed class ProductService : IProductService
{
private readonly HttpClient _httpClient;
public ProductService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public Task<string> GetAsync()
{
return Observable
.FromAsync(() => _httpClient.GetAsync("http://www.mocky.io/v2/5e307edf3200005d00858b49"))
.SubscribeOn(TaskPoolScheduler.Default)
.Retry(5)
.Timeout(TimeSpan.FromSeconds(5))
.Do(x => Console.WriteLine($"Is message successful? {x.IsSuccessStatusCode}"))
.SelectMany(async responseMessage =>
{
var response = await responseMessage.Content.ReadAsStringAsync();
return response;
})
.Catch<string, TimeoutException>(_ => Observable.Return("Timeout"))
.Catch<string, Exception>(ex => Observable.Return(ex.Message))
.ToTask();
}
}
public class ProductServiceTests
{
[Fact]
public async Task GetAsync_ShouldReturnText_WhenRequestIsSent()
{
// Arrange
var messageHandler = new MockHttpMessageHandler("Stuff I want to return", HttpStatusCode.OK);
var httpClient = new HttpClient(messageHandler);
var sut = new ProductService(httpClient);
// Act
var result = await sut.GetAsync();
// Assert
result.Should().Be("Stuff I want to return");
}
// TODO: Unhappy path
}
I am trying to make an PostAsync call using IHttpClientFactory , The cancellation token is working fine and exception is caught by CatchBlock.
But when trying to mock the method the Cancellation token is false and catch block is not caught
Below code for controller and Moq class
ValuesController.cs
[Route("[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<ActionResult> Get()
{
try
{
var client = _httpClientFactory.CreateClient("Test");//Statup register this in startup.cs
/*services.AddHttpClient("Test", httpClient =>{});*/
apiTable table = new apiTable();
table.Name = "Asma Nadeem";
table.Roll = "6655";
string json = JsonConvert.SerializeObject(table);
CancellationTokenSource source = new CancellationTokenSource(1);
StringContent httpContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://jsonplaceholder.typicode.com/posts", httpContent, source.Token);
//Source.Token is false when running the below MOQ test case
string result = "" + response.Content + " : " + response.StatusCode;
return StatusCode(200, result);
}
catch (OperationCanceledException e)
{
return null;
}
catch (Exception e)
{
return null;
}
}
}
MOQ Class
UnitTest1.cs
public class UnitTest1
{
[Fact]
public void Test1()
{
//Arrange
var mockFactory = new Mock<IHttpClientFactory>();
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("{'name':thecodebuzz,'city':'USA'}"),
});
var client = new HttpClient(mockHttpMessageHandler.Object);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
ValuesController controller = new ValuesController(mockFactory.Object);
//Act
var result = controller.Get() ;
//Assert
Assert.NotNull(result);
//Assert.Equal(HttpStatusCode.OK, (HttpStatusCode)result.StatusCode);
}
}
If you want to assess the catch branch then setup up your mock to throw an OperationCanceledException
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ThrowsAsync(new OperationCanceledException(...));
I am dealing with a piece of code that looks like this:
public class Uploader : IUploader
{
public Uploader()
{
// assign member variables to dependency injected interface implementations
}
public async Task<string> Upload(string url, string data)
{
HttpResponseMessage result;
try
{
var handler = new HttpClientHandler();
var client = new HttpClient(handler);
result = await client.PostAsync(url, new FormUrlEncodedContent(data));
if (result.StatusCode != HttpStatusCode.OK)
{
return "Some Error Message";
}
else
{
return null; // Success!
}
}
catch (Exception ex)
{
// do some fancy stuff here
}
}
}
I am trying to unit test the Upload function. In particular, I need to mock the HttpClient. After reading the other answers on here and these two articles, I know that one of the better ways to solve this is to mock the HttpMessageHandler instead and pass that to HttpClient and have it return whatever I want.
So, I started along that path by first passing in HttpClient in the constructor as a dependency:
public class Uploader : IUploader
{
private readonly HttpClient m_httpClient; // made this a member variable
public Uploader(HttpClient httpClient) // dependency inject this
{
m_httpClient = httpClient;
}
public async Task<string> Upload(string url, string data)
{
HttpResponseMessage result;
try
{
var handler = new HttpClientHandler();
result = await m_httpClient.PostAsync(url, new FormUrlEncodedContent(data));
if (result.StatusCode != HttpStatusCode.OK)
{
return "Some Error Message";
}
else
{
return null; // Success!
}
}
catch (Exception ex)
{
// do some fancy stuff here
}
}
}
and adding: services.AddSingleton<HttpClient>(); to the ConfigureServices method of Startup.cs.
But now I face a slight issue where the original code specifically creates a HttpClientHandler to pass in. How then do I refactor that to take in a mockable handler?
I find the simplest way is to continue using HttpClient, but pass in a mocking HttpClientHandler such as https://github.com/richardszalay/mockhttp
Code sample from the link above:
var mockHttp = new MockHttpMessageHandler();
mockHttp.When("http://localhost/api/user/*")
.Respond("application/json", "{'name' : 'Test McGee'}");
// Inject the handler or client into your application code
var client = mockHttp.ToHttpClient();
var response = await client.GetAsync("http://localhost/api/user/1234");
var json = await response.Content.ReadAsStringAsync();
Console.Write(json); // {'name' : 'Test McGee'}
The Dependency Injection framework built into .NET Core ignores internal constructors, so it will call the parameter-less constructor in this scenario.
public sealed class Uploader : IUploader
{
private readonly HttpClient m_httpClient;
public Uploader() : this(new HttpClientHandler())
{
}
internal Uploader(HttpClientHandler handler)
{
m_httpClient = new HttpClient(handler);
}
// regular methods
}
In your unit tests, you can use the constructor accepting the HttpClientHandler:
[Fact]
public async Task ShouldDoSomethingAsync()
{
var mockHttp = new MockHttpMessageHandler();
mockHttp.When("http://myserver.com/upload")
.Respond("application/json", "{'status' : 'Success'}");
var uploader = new Uploader(mockHttp);
var result = await uploader.UploadAsync();
Assert.Equal("Success", result.Status);
}
Normally I'm not a big fan of having an internal constructor to facilitate testing, however, I find this more obvious and self-contained than registering a shared HttpClient.
HttpClientFactory might be another good option, but I haven't played around with that too much, so I'll just give info on what I've found useful myself.
One way would be to abstract your HTTP functionality into a service i.e. HttpService which implements an interface of IHttpService:
IHttpService
public interface IHttpService
{
Task<HttpResponseMessage> Post(Uri url, string payload, Dictionary<string, string> headers = null);
}
HttpService
public class HttpService : IHttpService
{
private static HttpClient _httpClient;
private const string MimeTypeApplicationJson = "application/json";
public HttpService()
{
_httpClient = new HttpClient();
}
private static async Task<HttpResponseMessage> HttpSendAsync(HttpMethod method, Uri url, string payload,
Dictionary<string, string> headers = null)
{
var request = new HttpRequestMessage(method, url);
request.Headers.Add("Accept", MimeTypeApplicationJson);
if (headers != null)
{
foreach (var header in headers)
{
request.Headers.Add(header.Key, header.Value);
}
}
if (!string.IsNullOrWhiteSpace(payload))
request.Content = new StringContent(payload, Encoding.UTF8, MimeTypeApplicationJson);
return await _httpClient.SendAsync(request);
}
public async Task<HttpResponseMessage> Post(Uri url, string payload, Dictionary<string, string> headers = null)
{
return await HttpSendAsync(HttpMethod.Post, url, payload, headers);
}
}
Add to your services:
services.AddSingleton<IHttpService, HttpService>();
In your class you would then inject IHttpService as a dependency:
public class Uploader : IUploader
{
private readonly IHttpService _httpService; // made this a member variable
public Uploader(IHttpService httpService) // dependency inject this
{
_httpService = httpService;
}
public async Task<string> Upload(string url, string data)
{
HttpResponseMessage result;
try
{
result = await _httpService.PostAsync(new Uri(url), data);
if (result.StatusCode != HttpStatusCode.OK)
{
return "Some Error Message";
}
else
{
return null; // Success!
}
}
catch (Exception ex)
{
// do some fancy stuff here
}
}
}
You could then use Moq to mock HttpService in your unit test:
[TestClass]
public class UploaderTests
{
private Mock<IHttpService> _mockHttpService = new Mock<IHttpService>();
[TestMethod]
public async Task WhenStatusCodeIsNot200Ok_ThenErrorMessageReturned()
{
// arrange
var uploader = new Uploader(_mockHttpService.Object);
var url = "someurl.co.uk";
var data = "data";
// need to setup your mock to return the response you want to test
_mockHttpService
.Setup(s => s.PostAsync(url, data))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.InternalServerError));
// act
var result = await uploader.Upload(new Uri(url), data);
// assert
Assert.AreEqual("Some Error Message", result);
}
[TestMethod]
public async Task WhenStatusCodeIs200Ok_ThenNullReturned()
{
// arrange
var uploader = new Uploader(_mockHttpService.Object);
var url = "someurl.co.uk";
var data = "data";
// need to setup your mock to return the response you want to test
_mockHttpService
.Setup(s => s.PostAsync(new Uri(url), data))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
// act
var result = await uploader.Upload(url, data);
// assert
Assert.AreEqual(null, result);
}
}
I am using moq in XUnit test but for some reason the mock is not working properly. Here's my unit test:
[Fact]
public async Task SampleUnitTest()
{
//Arrange
var httpClient = new HttpClient(new FakeHttpMessageHandler());
_mockConstructRequest.Setup(x => x.ConstructRequestString(searchRequestModel))
.Returns("a sample string");
var service = new LibraryService(_mockConstructRequest.Object);
//Act
var response = service.GetResponse(new Request(), httpClient);
//Assert
response.Should().BeNull();
}
private class FakeHttpMessageHandler : HttpMessageHandler
{
public Func<HttpRequestMessage, CancellationToken, HttpResponseMessage> HttpRequestHandler { get; set; } =
(r, c) =>
new HttpResponseMessage
{
ReasonPhrase = r.RequestUri.AbsoluteUri,
StatusCode = HttpStatusCode.OK
};
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(HttpRequestHandler(request, cancellationToken));
}
}
And here is the actual code and I am trying to test GetResponse method.
public class LibraryService : ILibraryService
{
private IConfiguration _configuration;
private IRequestConstructor _requestContructor;
public LibraryService (IRequestConstructor requestConstructor)
{
_requestConstructor = requestConstructor;
}
public async Task<Response> GetResponse(Request request, HttpClient client)
{
//construct request
string requestString = _constructRequestString.ConstructRequestString(request, client);
return null;
}
}
public class RequestContructor : IRequestContructor
{
public string ConstructRequestString(Request request)
{
return "a request string";
}
}
I was trying to step through the code from my unit test but when the break point is at this line, requestString variable is null while it is supposed to return "a sample string". Anyone knows why?
string requestString = _constructRequestString.ConstructRequestString(request, client);
As far as I can see you are mocking incorrectly:
Your mock:
_mockConstructRequest.Setup(x => x.ConstructRequestString(searchRequestModel))
.Returns("a sample string");
Method you are calling:
_constructRequestString.ConstructRequestString(request, client);
Should not it be something like this:
_mockConstructRequest.Setup(x => x.ConstructRequestString(It.IsAny<Request>(),It.IsAny<HttpClient>()))
.Returns("a sample string");
On top of that:
Try to initialize your mocks and your "classUnderTest" in constructor instead of in each test, it will run each time before the test and will do everything for you. For example:
public class UnitTestClass{
private readonly ClassUnderTest _classUnderTest;
private readonly Mock<ClassUnderTestDependecy> mockedInstance;
public UnitTestClass {
mockedInstance= new Mock<ClassUnderTestDependecy>();
_classUnderTest= new ClassUnderTest (ClassUnderTestDependecy.Object);
}
}
I'm having some challenges trying to use Moq with RestSharp. Maybe it's it my misunderstanding of Moq but for some reason I keep on getting a null reference exception when trying to Mock a RestResponse.
Here is my unit test.
[Test]
public void GetAll_Method_Throws_exception_if_response_Data_is_Null()
{
var restClient = new Mock<IRestClient>();
restClient.Setup(x => x.Execute(It.IsAny<IRestRequest>()))
.Returns(new RestResponse<RootObjectList>
{
StatusCode = HttpStatusCode.OK,
Content = null
} );
var client = new IncidentRestClient(restClient.Object);
Assert.Throws<Exception>(() => client.GetAll());
}
Here is my actually implementation:
public class IncidentRestClient : IIncidentRestClient
{
private readonly IRestClient client;
private readonly string url = "some url here";
public IncidentRestClient()
{
client = new RestClient { BaseUrl = new Uri(url) };
}
public RootObjectList GetAll()
{
var request = new RestRequest("api/now/table/incident", Method.GET) { RequestFormat = DataFormat.Json };
request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
IRestResponse<RootObjectList> response = client.Execute<RootObjectList>(request);
if (response.Data == null)
throw new Exception(response.ErrorException.ToString());
return response.Data;
}
}
For some reason response object is null. Could it be I'm mocking the return object incorrectly?
For disclosure purposes, I am assuming that your IncidentRestClient has a constructor that takes an IRestClient instance as a parameter and uses it to set the client member.
It looks like, in your test, you are running Setup for a different overload of Execute than the one you are using. Instead of:
.Setup(x => x.Execute(
try:
.Setup(x => x.Execute<RootObjectList>(