I have a method using RestSharp (110.2.0) that I'd like to unit test but am having difficulty.
Sample method:
private IRestClient _restClient;
public async Task<string> GetToken()
{
var pw = await _vault.GetValue("pw");
var un = await _vault.GetValue("un");
var request = new RestRequest(new Uri("login"));
request.AddJsonBody(new
{
Username = un,
Password = pw
});
var response = await _restClient.ExecutePostAsync<string>(request);
return response.Data;
}
Sample test:
private AutoMocker _mocker;
[Fact]
public async Task SomeTest()
{
_mocker.GetMock<IRestClient>()
.Setup(m => m.ExecuteAsync(It.Is<RestRequest>(r => r.Resource == "login"), It.IsAny<CancellationToken>()))
.ReturnsASync(new RestResponse
{
StatusCode = HttpStatusCode.OK, ResponseStatus = ResponseStatus.Completed,
IsSuccessStatusCode = true,
Content = "authToken",
});
var result = await _uut.GetToken();
Assert.Equal("authToken", result);
}
For the sake of this scenario, ignore that I'm essentially testing that my mock returns what I want. Actual code is more comprehensive and the http stuff is just a small step in the process (but is the blocker right now).
Running that as is, I get a null reference exception. Using answers from this question I apply the following changes to the test:
[Fact]
public async Task SomeTest()
{
var serializerConfig = new SerializerConfig();
serializerConfig.UseDefaultSerializers();
_mocker.GetMock<IRestClient>()
.Setup(m => m.Serializers)
.Returns(new RestSerializers(serializerConfig));
...rest of test code
This resolves the null reference exception, but response.Data
is always null. I can see the expected value in content
, but not in Data
.
I've attempted to change the mock setup to return this instead:
.ReturnsAsync(new RestResponse<string>(new RestRequest())
{
StatusCode = HttpStatusCode.OK, ResponseStatus = ResponseStatus.Completed,
IsSuccessStatusCode = true,
Content = "authToken",
Data = "authToken"
});
But that changes nothing. I've also added ContentType = "application/json; charset=utf-8"
to the mocked response, again with no success.
I am aware of the suggestion at RestSharp Docs, but it is currently impractical for me.
Extrapolating from the suggestion the RestSharp Docs, I modified my test to look like this:
public class TestClass
{
public TestClass()
{
_mocker = new AutoMocker();
_mockHttp = new MockHttpMessageHandler(); //from RichardSzalay.MockHttp
_mocker.Use<IRestClient>(new RestClient(new RestClientOptions("http://localhost"){ ConfigureMessageHandler = _ => _mockHttp }));
_uut = _mocker.CreateInstance<ClassToTest>();
}
[Fact]
public async Task SomeTest()
{
_mockHttp
.When("*/REST/Login")
.Respond("application/json", JsonConvert.SerializeObject("authToken"));
var result = await _uut.GetToken();
Assert.Equal("authToken", result);
}
}
This works and is actually a much cleaner implementation than I expected. Initially I was worried that I wouldn't be able to essentially modify the MockHttpMessageHandler after assigning it to the IRestClient, but that is not the case.