Skip to content

Commit

Permalink
Updated structure to support lazy invocation of http requests. (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
savpek authored Jun 21, 2018
1 parent e631a36 commit d21f50c
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ public void WhenHeadersAreDefined_ThenPassThemToApi()
.ExpectStatusCode(HttpStatusCode.NoContent);

TestHost.Run<TestStartup>().Invoking(x => x.Get("/headertest/",
headers: new Dictionary<string, string> {{"somethingElse", "somevalue"}}))
headers: new Dictionary<string, string> {{"somethingElse", "somevalue"}})
.ExpectStatusCode(HttpStatusCode.NoContent))
.Should().Throw<InvalidOperationException>();
}
}
Expand Down
43 changes: 25 additions & 18 deletions Protacon.NetCore.WebApi.TestUtil/CallResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,33 @@

namespace Protacon.NetCore.WebApi.TestUtil
{
public class CallResponse
public class Call
{
private readonly HttpResponseMessage _response;
private HttpStatusCode? _expectedCode;
private Func<HttpResponseMessage> _httpCall;
private readonly Lazy<HttpResponseMessage> _response;

public CallResponse(HttpResponseMessage response)
public Call(Func<HttpResponseMessage> httpCall)
{
_response = response;
_response = new Lazy<HttpResponseMessage>(httpCall);
_httpCall = httpCall;
}

public CallResponse ExpectStatusCode(HttpStatusCode code)
public Call ExpectStatusCode(HttpStatusCode code)
{
if (_response.StatusCode != code)
if (_response.Value.StatusCode != code)
{
throw new ExpectedStatusCodeException($"Expected statuscode '{code}' but got '{(int)_response.StatusCode}'");
throw new ExpectedStatusCodeException($"Expected statuscode '{code}' but got '{(int)_response.Value.StatusCode}'");
}

_expectedCode = code;

return this;
}

public CallResponse HeaderPassing(string header, Action<string> assertsForValue)
public Call HeaderPassing(string header, Action<string> assertsForValue)
{
var match = _response.Headers
var match = _response.Value.Headers
.SingleOrDefault(x => x.Key == header);

if (match.Equals(default(KeyValuePair<string, IEnumerable<string>>)))
Expand All @@ -44,21 +46,21 @@ public CallResponse HeaderPassing(string header, Action<string> assertsForValue)

private string HeadersAsReadableList()
{
return _response.Headers.Select(x => x.Key.ToString()).Aggregate("", (a, b) => $"{a}, {b}");
return _response.Value.Headers.Select(x => x.Key.ToString()).Aggregate("", (a, b) => $"{a}, {b}");
}

public CallData<T> WithContentOf<T>()
{
var code = (int)_response.StatusCode;
var code = (int)_response.Value.StatusCode;

if ((code > 299 || code < 199) && code != (int?)_expectedCode)
throw new ExpectedStatusCodeException(
$"Tried to get data from non ok statuscode response, expected status is '2xx' or '{_expectedCode}' but got '{code}' with content '{_response.Content.ReadAsStringAsync().Result}'");
$"Tried to get data from non ok statuscode response, expected status is '2xx' or '{_expectedCode}' but got '{code}' with content '{_response.Value.Content.ReadAsStringAsync().Result}'");

if (!_response.Content.Headers.Contains("Content-Type"))
if (!_response.Value.Content.Headers.Contains("Content-Type"))
throw new InvalidOperationException("Response didn't contain any 'Content-Type'. Reason may be that you didn't return anything?");

var contentType = _response.Content.Headers.Single(x => x.Key == "Content-Type").Value.FirstOrDefault() ?? "";
var contentType = _response.Value.Content.Headers.Single(x => x.Key == "Content-Type").Value.FirstOrDefault() ?? "";

switch (contentType)
{
Expand All @@ -68,27 +70,32 @@ public CallData<T> WithContentOf<T>()
if(typeof(T) != typeof(byte[]))
throw new InvalidOperationException("Only output type of 'byte[]' is supported for 'application/pdf'.");

var data = (object)_response.Content.ReadAsByteArrayAsync().Result.ToArray();
var data = (object)_response.Value.Content.ReadAsByteArrayAsync().Result.ToArray();
return new CallData<T>((T)data);
default:
if (typeof(T) != typeof(string))
throw new InvalidOperationException($"Only output type of 'string' is supported for '{contentType}'.");

var result = (object)_response.Content.ReadAsStringAsync().Result;
var result = (object)_response.Value.Content.ReadAsStringAsync().Result;
return new CallData<T>((T)result);
}
}

internal Call Clone()
{
return new Call(_httpCall);
}

private CallData<T> ParseJson<T>()
{
try
{
var asObject = JsonConvert.DeserializeObject<T>(_response.Content.ReadAsStringAsync().Result);
var asObject = JsonConvert.DeserializeObject<T>(_response.Value.Content.ReadAsStringAsync().Result);
return new CallData<T>(asObject);
}
catch (JsonSerializationException)
{
throw new InvalidOperationException($"Cannot serialize '{_response.Content.ReadAsStringAsync().Result}' as type '{typeof(T)}'");
throw new InvalidOperationException($"Cannot serialize '{_response.Value.Content.ReadAsStringAsync().Result}' as type '{typeof(T)}'");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ namespace Protacon.NetCore.WebApi.TestUtil.Extensions
{
public static class CallResponseExtensions
{
public static CallResponse WaitForStatusCode(this CallResponse response, HttpStatusCode statusCode, TimeSpan timeout)
public static Call WaitForStatusCode(this Call call, HttpStatusCode statusCode, TimeSpan timeout)
{
DateTime endAt = DateTime.UtcNow.Add(timeout);

while (true)
{
try
{
return response.ExpectStatusCode(statusCode);
return call.Clone().ExpectStatusCode(statusCode);
}
catch (ExpectedStatusCodeException ex)
{
Expand Down
70 changes: 41 additions & 29 deletions Protacon.NetCore.WebApi.TestUtil/TestHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,49 +12,61 @@ namespace Protacon.NetCore.WebApi.TestUtil
{
public static class TestHost
{
public static CallResponse Get(this TestServer server, string uri, Dictionary<string, string> headers = null)
public static Call Get(this TestServer server, string uri, Dictionary<string, string> headers = null)
{
using (var client = server.CreateClient())
return new Call(() =>
{
AddHeadersIfAny(headers, client);
return new CallResponse(client.GetAsync(uri).Result);
}
using (var client = server.CreateClient())
{
AddHeadersIfAny(headers, client);
return client.GetAsync(uri).Result;
}
});
}

public static CallResponse Post(this TestServer server, string path, object data, Dictionary<string, string> headers = null)
public static Call Post(this TestServer server, string path, object data, Dictionary<string, string> headers = null)
{
using (var client = server.CreateClient())
return new Call(() =>
{
AddHeadersIfAny(headers, client);

var content = JsonConvert.SerializeObject(data);
return new CallResponse(client.PostAsync(path, new StringContent(content, Encoding.UTF8, "application/json")).Result);
}
using (var client = server.CreateClient())
{
AddHeadersIfAny(headers, client);

var content = JsonConvert.SerializeObject(data);
return client.PostAsync(path, new StringContent(content, Encoding.UTF8, "application/json")).Result;
}
});
}

public static CallResponse Put(this TestServer server, string path, object data, Dictionary<string, string> headers = null)
public static Call Put(this TestServer server, string path, object data, Dictionary<string, string> headers = null)
{
using (var client = server.CreateClient())
return new Call(() =>
{
AddHeadersIfAny(headers, client);

var content = JsonConvert.SerializeObject(data);
return new CallResponse(client
.PutAsync(path, new StringContent(content, Encoding.UTF8, "application/json"))
.Result);
}
using (var client = server.CreateClient())
{
AddHeadersIfAny(headers, client);

var content = JsonConvert.SerializeObject(data);
return client
.PutAsync(path, new StringContent(content, Encoding.UTF8, "application/json"))
.Result;
}
});
}

public static CallResponse Delete(this TestServer server, string path, Dictionary<string, string> headers = null)
public static Call Delete(this TestServer server, string path, Dictionary<string, string> headers = null)
{
using (var client = server.CreateClient())
return new Call(() =>
{
AddHeadersIfAny(headers, client);

return new CallResponse(client
.DeleteAsync(path)
.Result);
}
using (var client = server.CreateClient())
{
AddHeadersIfAny(headers, client);

return client
.DeleteAsync(path)
.Result;
}
});
}

private static void AddHeadersIfAny(Dictionary<string, string> headers, HttpClient client)
Expand Down

0 comments on commit d21f50c

Please sign in to comment.