Unit Testing Class That Wraps HttpClient












1















I am in the process of writing unit tests for a new project we've created and one of the issues I've come across is how to properly unit test something that effectively wraps HttpClient. In this case, I have written a RestfulService class that exposes basic methods for calling a REST service from C#.



Here is the simple interface that the class implements:



public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);

Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);

Task<FileResponse?> Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}


and here's is a trimmed down version of the implementation for example purposes:



public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
/* boiler plate code for config and what have you */
private string Host => "http://localhost";
private NetworkCredential Credentials => new NetworkCredential("sampleUser", "samplePassword");
private string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private HttpClient Client => this.httpClient = this.httpClient ?? new HttpClient();
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


As you can see from the implementation it's a pretty thin wrapper that handles things like adding the auth headers (pulled from config) and some other small basic things.



My question: How can I mock the call to Client.SendAsync to return predetermined responses to verify deserialization is happening properly and that the auth headers are added? Would it make more sense to move the adding of the auth headers out of DoRequest and Mock the implementation of DoRequest before running my test?










share|improve this question


















  • 2





    Mocking HttpClient is Hard. See also.

    – Robert Harvey
    Nov 19 '18 at 20:45













  • @RobertHarvey Thanks for the link, I'm going to read up on that now.

    – Adam H
    Nov 19 '18 at 20:47











  • This should be tested against actual services by using actual HttpClient.

    – Fabio
    Nov 19 '18 at 23:24











  • @Fabio thanks for the reply, however, testing against the actual services that it is calling would be a regression test and beyond the scope of a unit test. I have found a way to accomplish what I need and will be posting an answer to this question shortly.

    – Adam H
    Nov 20 '18 at 15:10











  • Have you considered using Flurl? It's a thin wrapper above HttpClient. It has a great syntax, and is testable.

    – mason
    Nov 20 '18 at 15:43
















1















I am in the process of writing unit tests for a new project we've created and one of the issues I've come across is how to properly unit test something that effectively wraps HttpClient. In this case, I have written a RestfulService class that exposes basic methods for calling a REST service from C#.



Here is the simple interface that the class implements:



public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);

Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);

Task<FileResponse?> Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}


and here's is a trimmed down version of the implementation for example purposes:



public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
/* boiler plate code for config and what have you */
private string Host => "http://localhost";
private NetworkCredential Credentials => new NetworkCredential("sampleUser", "samplePassword");
private string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private HttpClient Client => this.httpClient = this.httpClient ?? new HttpClient();
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


As you can see from the implementation it's a pretty thin wrapper that handles things like adding the auth headers (pulled from config) and some other small basic things.



My question: How can I mock the call to Client.SendAsync to return predetermined responses to verify deserialization is happening properly and that the auth headers are added? Would it make more sense to move the adding of the auth headers out of DoRequest and Mock the implementation of DoRequest before running my test?










share|improve this question


















  • 2





    Mocking HttpClient is Hard. See also.

    – Robert Harvey
    Nov 19 '18 at 20:45













  • @RobertHarvey Thanks for the link, I'm going to read up on that now.

    – Adam H
    Nov 19 '18 at 20:47











  • This should be tested against actual services by using actual HttpClient.

    – Fabio
    Nov 19 '18 at 23:24











  • @Fabio thanks for the reply, however, testing against the actual services that it is calling would be a regression test and beyond the scope of a unit test. I have found a way to accomplish what I need and will be posting an answer to this question shortly.

    – Adam H
    Nov 20 '18 at 15:10











  • Have you considered using Flurl? It's a thin wrapper above HttpClient. It has a great syntax, and is testable.

    – mason
    Nov 20 '18 at 15:43














1












1








1


0






I am in the process of writing unit tests for a new project we've created and one of the issues I've come across is how to properly unit test something that effectively wraps HttpClient. In this case, I have written a RestfulService class that exposes basic methods for calling a REST service from C#.



Here is the simple interface that the class implements:



public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);

Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);

Task<FileResponse?> Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}


and here's is a trimmed down version of the implementation for example purposes:



public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
/* boiler plate code for config and what have you */
private string Host => "http://localhost";
private NetworkCredential Credentials => new NetworkCredential("sampleUser", "samplePassword");
private string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private HttpClient Client => this.httpClient = this.httpClient ?? new HttpClient();
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


As you can see from the implementation it's a pretty thin wrapper that handles things like adding the auth headers (pulled from config) and some other small basic things.



My question: How can I mock the call to Client.SendAsync to return predetermined responses to verify deserialization is happening properly and that the auth headers are added? Would it make more sense to move the adding of the auth headers out of DoRequest and Mock the implementation of DoRequest before running my test?










share|improve this question














I am in the process of writing unit tests for a new project we've created and one of the issues I've come across is how to properly unit test something that effectively wraps HttpClient. In this case, I have written a RestfulService class that exposes basic methods for calling a REST service from C#.



Here is the simple interface that the class implements:



public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);

Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);

Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);

Task<FileResponse?> Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}


and here's is a trimmed down version of the implementation for example purposes:



public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
/* boiler plate code for config and what have you */
private string Host => "http://localhost";
private NetworkCredential Credentials => new NetworkCredential("sampleUser", "samplePassword");
private string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private HttpClient Client => this.httpClient = this.httpClient ?? new HttpClient();
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


As you can see from the implementation it's a pretty thin wrapper that handles things like adding the auth headers (pulled from config) and some other small basic things.



My question: How can I mock the call to Client.SendAsync to return predetermined responses to verify deserialization is happening properly and that the auth headers are added? Would it make more sense to move the adding of the auth headers out of DoRequest and Mock the implementation of DoRequest before running my test?







c# unit-testing xunit






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 19 '18 at 20:43









Adam HAdam H

972115




972115








  • 2





    Mocking HttpClient is Hard. See also.

    – Robert Harvey
    Nov 19 '18 at 20:45













  • @RobertHarvey Thanks for the link, I'm going to read up on that now.

    – Adam H
    Nov 19 '18 at 20:47











  • This should be tested against actual services by using actual HttpClient.

    – Fabio
    Nov 19 '18 at 23:24











  • @Fabio thanks for the reply, however, testing against the actual services that it is calling would be a regression test and beyond the scope of a unit test. I have found a way to accomplish what I need and will be posting an answer to this question shortly.

    – Adam H
    Nov 20 '18 at 15:10











  • Have you considered using Flurl? It's a thin wrapper above HttpClient. It has a great syntax, and is testable.

    – mason
    Nov 20 '18 at 15:43














  • 2





    Mocking HttpClient is Hard. See also.

    – Robert Harvey
    Nov 19 '18 at 20:45













  • @RobertHarvey Thanks for the link, I'm going to read up on that now.

    – Adam H
    Nov 19 '18 at 20:47











  • This should be tested against actual services by using actual HttpClient.

    – Fabio
    Nov 19 '18 at 23:24











  • @Fabio thanks for the reply, however, testing against the actual services that it is calling would be a regression test and beyond the scope of a unit test. I have found a way to accomplish what I need and will be posting an answer to this question shortly.

    – Adam H
    Nov 20 '18 at 15:10











  • Have you considered using Flurl? It's a thin wrapper above HttpClient. It has a great syntax, and is testable.

    – mason
    Nov 20 '18 at 15:43








2




2





Mocking HttpClient is Hard. See also.

– Robert Harvey
Nov 19 '18 at 20:45







Mocking HttpClient is Hard. See also.

– Robert Harvey
Nov 19 '18 at 20:45















@RobertHarvey Thanks for the link, I'm going to read up on that now.

– Adam H
Nov 19 '18 at 20:47





@RobertHarvey Thanks for the link, I'm going to read up on that now.

– Adam H
Nov 19 '18 at 20:47













This should be tested against actual services by using actual HttpClient.

– Fabio
Nov 19 '18 at 23:24





This should be tested against actual services by using actual HttpClient.

– Fabio
Nov 19 '18 at 23:24













@Fabio thanks for the reply, however, testing against the actual services that it is calling would be a regression test and beyond the scope of a unit test. I have found a way to accomplish what I need and will be posting an answer to this question shortly.

– Adam H
Nov 20 '18 at 15:10





@Fabio thanks for the reply, however, testing against the actual services that it is calling would be a regression test and beyond the scope of a unit test. I have found a way to accomplish what I need and will be posting an answer to this question shortly.

– Adam H
Nov 20 '18 at 15:10













Have you considered using Flurl? It's a thin wrapper above HttpClient. It has a great syntax, and is testable.

– mason
Nov 20 '18 at 15:43





Have you considered using Flurl? It's a thin wrapper above HttpClient. It has a great syntax, and is testable.

– mason
Nov 20 '18 at 15:43












1 Answer
1






active

oldest

votes


















1














I was able to figure this out using an accessor for the HttpClient and then mocking out the HttpMessageHandler. Here is the code I used.



public interface IHttpClientAccessor
{
HttpClient HttpClient
{
get;
}
}

public class HttpClientAccessor : IHttpClientAccessor
{
public HttpClientAccessor()
{
this.HttpClient = new HttpClient();
}

public HttpClient HttpClient
{
get;
}
}

public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);
Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);
Task<FileResponse? > Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}

public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
private IHttpClientAccessor httpClientAccessor;
public RestfulService(IConfigurationService configurationService, IHttpClientAccessor httpClientAccessor)
{
this.ConfigurationService = configurationService;
this.httpClientAccessor = httpClientAccessor;
}

public string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private IConfigurationService ConfigurationService
{
get;
}

private string Host => "http://locahost/";
private NetworkCredential Credentials => this.credentials ?? new NetworkCredential("someUser", "somePassword");
private HttpClient Client => this.httpClient = this.httpClient ?? this.httpClientAccessor.HttpClient;
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


And here is the implementation for test cases:



private RestfulService SetupRestfulService(HttpResponseMessage returns, string userName = "notARealUser", string password = "notARealPassword")
{
var mockHttpAccessor = new Mock<IHttpClientAccessor>();
var mockHttpHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var testServiceEndpoints = Options.Create<Configuration.ServiceEndpoints>(new Configuration.ServiceEndpoints()
{OneEndPoint = "http://localhost/test", AnotherEndPoint = "http://localhost/test"});
var testAuth = Options.Create<AuthOptions>(new AuthOptions()
{Password = password, Username = userName});
mockHttpHandler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()).ReturnsAsync(returns).Verifiable();
mockHttpAccessor.SetupGet(p => p.HttpClient).Returns(new HttpClient(mockHttpHandler.Object));
return new RestfulService(new ConfigurationService(testServiceEndpoints, testAuth), mockHttpAccessor.Object);
}

[Fact]
public void TestAuthorizationHeader()
{
// notARealUser : notARealPassword
var expected = "Basic bm90QVJlYWxVc2VyOm5vdEFSZWFsUGFzc3dvcmQ=";
var service = this.SetupRestfulService(new HttpResponseMessage{StatusCode = HttpStatusCode.OK, Content = new StringContent("AuthorizationTest")});
Assert.Equal(expected, service.AuthHeader);
}

[Fact]
public async Task TestGetPlainString()
{
var service = this.SetupRestfulService(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("test") });
var result = await service.Get<string>("test", null, null);
Assert.Equal("test", result);
}


This allows me to pass the desired response into SetupRestfulService along with credentials and get back an object I can call my functions on. It's a little less than Ideal but it saves me from having to flesh out the entire adapter pattern and going down that rabbit hole.






share|improve this answer





















  • 1





    Similar to what I did here stackoverflow.com/a/45154289/5233410

    – Nkosi
    Nov 20 '18 at 15:41











  • @Nkosi wow, this is almost like bumping into a celebrity! I definitely read your posts on a couple of threads and armed with that info I hacked this together. I didn't get a chance in those threads to say it so I'll say it here, Thank You for your help.

    – Adam H
    Nov 20 '18 at 15:44











  • Glad to help. Happy Coding.

    – Nkosi
    Nov 20 '18 at 15:47











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382348%2funit-testing-class-that-wraps-httpclient%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














I was able to figure this out using an accessor for the HttpClient and then mocking out the HttpMessageHandler. Here is the code I used.



public interface IHttpClientAccessor
{
HttpClient HttpClient
{
get;
}
}

public class HttpClientAccessor : IHttpClientAccessor
{
public HttpClientAccessor()
{
this.HttpClient = new HttpClient();
}

public HttpClient HttpClient
{
get;
}
}

public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);
Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);
Task<FileResponse? > Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}

public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
private IHttpClientAccessor httpClientAccessor;
public RestfulService(IConfigurationService configurationService, IHttpClientAccessor httpClientAccessor)
{
this.ConfigurationService = configurationService;
this.httpClientAccessor = httpClientAccessor;
}

public string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private IConfigurationService ConfigurationService
{
get;
}

private string Host => "http://locahost/";
private NetworkCredential Credentials => this.credentials ?? new NetworkCredential("someUser", "somePassword");
private HttpClient Client => this.httpClient = this.httpClient ?? this.httpClientAccessor.HttpClient;
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


And here is the implementation for test cases:



private RestfulService SetupRestfulService(HttpResponseMessage returns, string userName = "notARealUser", string password = "notARealPassword")
{
var mockHttpAccessor = new Mock<IHttpClientAccessor>();
var mockHttpHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var testServiceEndpoints = Options.Create<Configuration.ServiceEndpoints>(new Configuration.ServiceEndpoints()
{OneEndPoint = "http://localhost/test", AnotherEndPoint = "http://localhost/test"});
var testAuth = Options.Create<AuthOptions>(new AuthOptions()
{Password = password, Username = userName});
mockHttpHandler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()).ReturnsAsync(returns).Verifiable();
mockHttpAccessor.SetupGet(p => p.HttpClient).Returns(new HttpClient(mockHttpHandler.Object));
return new RestfulService(new ConfigurationService(testServiceEndpoints, testAuth), mockHttpAccessor.Object);
}

[Fact]
public void TestAuthorizationHeader()
{
// notARealUser : notARealPassword
var expected = "Basic bm90QVJlYWxVc2VyOm5vdEFSZWFsUGFzc3dvcmQ=";
var service = this.SetupRestfulService(new HttpResponseMessage{StatusCode = HttpStatusCode.OK, Content = new StringContent("AuthorizationTest")});
Assert.Equal(expected, service.AuthHeader);
}

[Fact]
public async Task TestGetPlainString()
{
var service = this.SetupRestfulService(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("test") });
var result = await service.Get<string>("test", null, null);
Assert.Equal("test", result);
}


This allows me to pass the desired response into SetupRestfulService along with credentials and get back an object I can call my functions on. It's a little less than Ideal but it saves me from having to flesh out the entire adapter pattern and going down that rabbit hole.






share|improve this answer





















  • 1





    Similar to what I did here stackoverflow.com/a/45154289/5233410

    – Nkosi
    Nov 20 '18 at 15:41











  • @Nkosi wow, this is almost like bumping into a celebrity! I definitely read your posts on a couple of threads and armed with that info I hacked this together. I didn't get a chance in those threads to say it so I'll say it here, Thank You for your help.

    – Adam H
    Nov 20 '18 at 15:44











  • Glad to help. Happy Coding.

    – Nkosi
    Nov 20 '18 at 15:47
















1














I was able to figure this out using an accessor for the HttpClient and then mocking out the HttpMessageHandler. Here is the code I used.



public interface IHttpClientAccessor
{
HttpClient HttpClient
{
get;
}
}

public class HttpClientAccessor : IHttpClientAccessor
{
public HttpClientAccessor()
{
this.HttpClient = new HttpClient();
}

public HttpClient HttpClient
{
get;
}
}

public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);
Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);
Task<FileResponse? > Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}

public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
private IHttpClientAccessor httpClientAccessor;
public RestfulService(IConfigurationService configurationService, IHttpClientAccessor httpClientAccessor)
{
this.ConfigurationService = configurationService;
this.httpClientAccessor = httpClientAccessor;
}

public string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private IConfigurationService ConfigurationService
{
get;
}

private string Host => "http://locahost/";
private NetworkCredential Credentials => this.credentials ?? new NetworkCredential("someUser", "somePassword");
private HttpClient Client => this.httpClient = this.httpClient ?? this.httpClientAccessor.HttpClient;
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


And here is the implementation for test cases:



private RestfulService SetupRestfulService(HttpResponseMessage returns, string userName = "notARealUser", string password = "notARealPassword")
{
var mockHttpAccessor = new Mock<IHttpClientAccessor>();
var mockHttpHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var testServiceEndpoints = Options.Create<Configuration.ServiceEndpoints>(new Configuration.ServiceEndpoints()
{OneEndPoint = "http://localhost/test", AnotherEndPoint = "http://localhost/test"});
var testAuth = Options.Create<AuthOptions>(new AuthOptions()
{Password = password, Username = userName});
mockHttpHandler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()).ReturnsAsync(returns).Verifiable();
mockHttpAccessor.SetupGet(p => p.HttpClient).Returns(new HttpClient(mockHttpHandler.Object));
return new RestfulService(new ConfigurationService(testServiceEndpoints, testAuth), mockHttpAccessor.Object);
}

[Fact]
public void TestAuthorizationHeader()
{
// notARealUser : notARealPassword
var expected = "Basic bm90QVJlYWxVc2VyOm5vdEFSZWFsUGFzc3dvcmQ=";
var service = this.SetupRestfulService(new HttpResponseMessage{StatusCode = HttpStatusCode.OK, Content = new StringContent("AuthorizationTest")});
Assert.Equal(expected, service.AuthHeader);
}

[Fact]
public async Task TestGetPlainString()
{
var service = this.SetupRestfulService(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("test") });
var result = await service.Get<string>("test", null, null);
Assert.Equal("test", result);
}


This allows me to pass the desired response into SetupRestfulService along with credentials and get back an object I can call my functions on. It's a little less than Ideal but it saves me from having to flesh out the entire adapter pattern and going down that rabbit hole.






share|improve this answer





















  • 1





    Similar to what I did here stackoverflow.com/a/45154289/5233410

    – Nkosi
    Nov 20 '18 at 15:41











  • @Nkosi wow, this is almost like bumping into a celebrity! I definitely read your posts on a couple of threads and armed with that info I hacked this together. I didn't get a chance in those threads to say it so I'll say it here, Thank You for your help.

    – Adam H
    Nov 20 '18 at 15:44











  • Glad to help. Happy Coding.

    – Nkosi
    Nov 20 '18 at 15:47














1












1








1







I was able to figure this out using an accessor for the HttpClient and then mocking out the HttpMessageHandler. Here is the code I used.



public interface IHttpClientAccessor
{
HttpClient HttpClient
{
get;
}
}

public class HttpClientAccessor : IHttpClientAccessor
{
public HttpClientAccessor()
{
this.HttpClient = new HttpClient();
}

public HttpClient HttpClient
{
get;
}
}

public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);
Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);
Task<FileResponse? > Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}

public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
private IHttpClientAccessor httpClientAccessor;
public RestfulService(IConfigurationService configurationService, IHttpClientAccessor httpClientAccessor)
{
this.ConfigurationService = configurationService;
this.httpClientAccessor = httpClientAccessor;
}

public string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private IConfigurationService ConfigurationService
{
get;
}

private string Host => "http://locahost/";
private NetworkCredential Credentials => this.credentials ?? new NetworkCredential("someUser", "somePassword");
private HttpClient Client => this.httpClient = this.httpClient ?? this.httpClientAccessor.HttpClient;
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


And here is the implementation for test cases:



private RestfulService SetupRestfulService(HttpResponseMessage returns, string userName = "notARealUser", string password = "notARealPassword")
{
var mockHttpAccessor = new Mock<IHttpClientAccessor>();
var mockHttpHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var testServiceEndpoints = Options.Create<Configuration.ServiceEndpoints>(new Configuration.ServiceEndpoints()
{OneEndPoint = "http://localhost/test", AnotherEndPoint = "http://localhost/test"});
var testAuth = Options.Create<AuthOptions>(new AuthOptions()
{Password = password, Username = userName});
mockHttpHandler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()).ReturnsAsync(returns).Verifiable();
mockHttpAccessor.SetupGet(p => p.HttpClient).Returns(new HttpClient(mockHttpHandler.Object));
return new RestfulService(new ConfigurationService(testServiceEndpoints, testAuth), mockHttpAccessor.Object);
}

[Fact]
public void TestAuthorizationHeader()
{
// notARealUser : notARealPassword
var expected = "Basic bm90QVJlYWxVc2VyOm5vdEFSZWFsUGFzc3dvcmQ=";
var service = this.SetupRestfulService(new HttpResponseMessage{StatusCode = HttpStatusCode.OK, Content = new StringContent("AuthorizationTest")});
Assert.Equal(expected, service.AuthHeader);
}

[Fact]
public async Task TestGetPlainString()
{
var service = this.SetupRestfulService(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("test") });
var result = await service.Get<string>("test", null, null);
Assert.Equal("test", result);
}


This allows me to pass the desired response into SetupRestfulService along with credentials and get back an object I can call my functions on. It's a little less than Ideal but it saves me from having to flesh out the entire adapter pattern and going down that rabbit hole.






share|improve this answer















I was able to figure this out using an accessor for the HttpClient and then mocking out the HttpMessageHandler. Here is the code I used.



public interface IHttpClientAccessor
{
HttpClient HttpClient
{
get;
}
}

public class HttpClientAccessor : IHttpClientAccessor
{
public HttpClientAccessor()
{
this.HttpClient = new HttpClient();
}

public HttpClient HttpClient
{
get;
}
}

public interface IRestfulService
{
Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null);
Task<T> Post<T>(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Put(string url, IDictionary<string, string> parameters, object bodyObject, IDictionary<string, string> headers = null);
Task<string> Delete(string url, object bodyObject, IDictionary<string, string> headers = null);
Task<FileResponse? > Download(string url, IDictionary<string, string> urlParams = null, IDictionary<string, string> headers = null);
}

public class RestfulService : IRestfulService
{
private HttpClient httpClient = null;
private NetworkCredential credentials = null;
private IHttpClientAccessor httpClientAccessor;
public RestfulService(IConfigurationService configurationService, IHttpClientAccessor httpClientAccessor)
{
this.ConfigurationService = configurationService;
this.httpClientAccessor = httpClientAccessor;
}

public string AuthHeader
{
get
{
if (this.Credentials != null)
{
return string.Format("Basic {0}", Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)));
}
else
{
return string.Empty;
}
}
}

private IConfigurationService ConfigurationService
{
get;
}

private string Host => "http://locahost/";
private NetworkCredential Credentials => this.credentials ?? new NetworkCredential("someUser", "somePassword");
private HttpClient Client => this.httpClient = this.httpClient ?? this.httpClientAccessor.HttpClient;
public async Task<T> Get<T>(string url, IDictionary<string, string> parameters, IDictionary<string, string> headers = null)
{
var result = await this.DoRequest(url, HttpMethod.Get, parameters, null, headers);
if (typeof (T) == typeof (string))
{
return (T)(object)result;
}
else
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(result);
}
}

private async Task<string> DoRequest(string url, HttpMethod method, IDictionary<string, string> urlParams = null, object bodyObject = null, IDictionary<string, string> headers = null)
{
string fullRequestUrl = string.Empty;
HttpResponseMessage response = null;
if (headers == null)
{
headers = new Dictionary<string, string>();
}

if (this.Credentials != null)
{
headers.Add("Authorization", this.AuthHeader);
}

headers.Add("Accept", "application/json");
fullRequestUrl = string.Format("{0}{1}{2}", this.Host.ToString(), url, urlParams?.ToQueryString());
using (var request = new HttpRequestMessage(method, fullRequestUrl))
{
request.AddHeaders(headers);
if (bodyObject != null)
{
request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(bodyObject), System.Text.Encoding.UTF8, "application/json");
}

response = await this.Client.SendAsync(request).ConfigureAwait(false);
}

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
var errDesc = response.ReasonPhrase;
if (!string.IsNullOrEmpty(content))
{
errDesc += " - " + content;
}

throw new HttpRequestException(string.Format("RestfulService: Error sending request to web service URL {0}. Reason: {1}", fullRequestUrl, errDesc));
}

return content;
}
}


And here is the implementation for test cases:



private RestfulService SetupRestfulService(HttpResponseMessage returns, string userName = "notARealUser", string password = "notARealPassword")
{
var mockHttpAccessor = new Mock<IHttpClientAccessor>();
var mockHttpHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var testServiceEndpoints = Options.Create<Configuration.ServiceEndpoints>(new Configuration.ServiceEndpoints()
{OneEndPoint = "http://localhost/test", AnotherEndPoint = "http://localhost/test"});
var testAuth = Options.Create<AuthOptions>(new AuthOptions()
{Password = password, Username = userName});
mockHttpHandler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()).ReturnsAsync(returns).Verifiable();
mockHttpAccessor.SetupGet(p => p.HttpClient).Returns(new HttpClient(mockHttpHandler.Object));
return new RestfulService(new ConfigurationService(testServiceEndpoints, testAuth), mockHttpAccessor.Object);
}

[Fact]
public void TestAuthorizationHeader()
{
// notARealUser : notARealPassword
var expected = "Basic bm90QVJlYWxVc2VyOm5vdEFSZWFsUGFzc3dvcmQ=";
var service = this.SetupRestfulService(new HttpResponseMessage{StatusCode = HttpStatusCode.OK, Content = new StringContent("AuthorizationTest")});
Assert.Equal(expected, service.AuthHeader);
}

[Fact]
public async Task TestGetPlainString()
{
var service = this.SetupRestfulService(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("test") });
var result = await service.Get<string>("test", null, null);
Assert.Equal("test", result);
}


This allows me to pass the desired response into SetupRestfulService along with credentials and get back an object I can call my functions on. It's a little less than Ideal but it saves me from having to flesh out the entire adapter pattern and going down that rabbit hole.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 20 '18 at 15:37

























answered Nov 20 '18 at 15:20









Adam HAdam H

972115




972115








  • 1





    Similar to what I did here stackoverflow.com/a/45154289/5233410

    – Nkosi
    Nov 20 '18 at 15:41











  • @Nkosi wow, this is almost like bumping into a celebrity! I definitely read your posts on a couple of threads and armed with that info I hacked this together. I didn't get a chance in those threads to say it so I'll say it here, Thank You for your help.

    – Adam H
    Nov 20 '18 at 15:44











  • Glad to help. Happy Coding.

    – Nkosi
    Nov 20 '18 at 15:47














  • 1





    Similar to what I did here stackoverflow.com/a/45154289/5233410

    – Nkosi
    Nov 20 '18 at 15:41











  • @Nkosi wow, this is almost like bumping into a celebrity! I definitely read your posts on a couple of threads and armed with that info I hacked this together. I didn't get a chance in those threads to say it so I'll say it here, Thank You for your help.

    – Adam H
    Nov 20 '18 at 15:44











  • Glad to help. Happy Coding.

    – Nkosi
    Nov 20 '18 at 15:47








1




1





Similar to what I did here stackoverflow.com/a/45154289/5233410

– Nkosi
Nov 20 '18 at 15:41





Similar to what I did here stackoverflow.com/a/45154289/5233410

– Nkosi
Nov 20 '18 at 15:41













@Nkosi wow, this is almost like bumping into a celebrity! I definitely read your posts on a couple of threads and armed with that info I hacked this together. I didn't get a chance in those threads to say it so I'll say it here, Thank You for your help.

– Adam H
Nov 20 '18 at 15:44





@Nkosi wow, this is almost like bumping into a celebrity! I definitely read your posts on a couple of threads and armed with that info I hacked this together. I didn't get a chance in those threads to say it so I'll say it here, Thank You for your help.

– Adam H
Nov 20 '18 at 15:44













Glad to help. Happy Coding.

– Nkosi
Nov 20 '18 at 15:47





Glad to help. Happy Coding.

– Nkosi
Nov 20 '18 at 15:47


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53382348%2funit-testing-class-that-wraps-httpclient%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to change which sound is reproduced for terminal bell?

Can I use Tabulator js library in my java Spring + Thymeleaf project?

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents