Using asp.net 5 TestServer to fix Api external call

I am trying to use TestServer to test my middleware. Somewhere in the middleware, my code calls api via HttpClient. I would like to make fun of it using the second TestServer, but I wonder if this is possible. I already tried, but I have an error: "Trying to connect ... but the server actively refused."

this is what the code looks like:

[Fact] public async Task Should_give_200_Response() { var server = TestServer.Create((app) => { app.UseMiddleware<DummyMiddleware>(); }); var fakeServer = TestServer.Create((app) => { app.UseMiddleware<FakeMiddleware>(); }); using(server) { using(fakeServer) { var response = await server.CreateClient().GetAsync("/somePath"); Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } } 

Somewhere in the DummyMiddleware code I'm doing

  HttpClient client = new HttpClient() { BaseAddress = "http://fakeUrl.com"}; var resp = client.GetAsync("/path/to/api"); 

URL: http://fakeUrl.com will mock fakeServer. but actually the real call http: // fakeUrl is issued over the network, but I would like it to get into fakeserver so that I can mock this api.

Imagine fakeserver, for example, would make fun of the Google Calendar api.

Update : using fakeServer In fact, fakeServer will listen to this URL: " http://fakeUrl.com ", and when you get the route "/ path / to / api", it will return for example a json object. I would like my fakeServer to return a mocking object. as a reminder, " http://fakeUrl.com/path/to/api " will be called somewhere in my code with an HttpClient object.

0
source share
1 answer

I found a solution, but with visual studio 2015, the CTP6 test sometimes passes, sometimes not ... it seems this is a Xunit problem, because when I debug, everything is fine ... but this is not a problem here

link to full code: github repo

here is the middleware that I want to check:

  using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using System.Net; using System.Net.Http; using System.Threading.Tasks; namespace Multi.Web.Api { public class MultiMiddleware { private readonly RequestDelegate next; public MultiMiddleware(RequestDelegate next) { this.next = next; } public async Task Invoke(HttpContext context, IClientProvider provider) { HttpClient calendarClient = null; HttpClient CalcClient = null; try { // //get the respective client // calendarClient = provider.GetClientFor("calendar"); CalcClient = provider.GetClientFor("calc"); // //call the calendar api // var calendarResponse = ""; if (context.Request.Path.Value == "/today") { calendarResponse = await calendarClient.GetStringAsync("http://www.calendarApi.io/today"); } else if (context.Request.Path.Value == "/yesterday") { calendarResponse = await calendarClient.GetStringAsync("http://www.calendarApi.io/yesterday"); } else { context.Response.StatusCode = (int)HttpStatusCode.NotFound; //does not process further return; } // //call another api // var calcResponse = await CalcClient.GetStringAsync("http://www.calcApi.io/count"); // // write the final response // await context.Response.WriteAsync(calendarResponse + " count is " + calcResponse); await next(context); } finally { if (calendarClient != null) { calendarClient.Dispose(); } if (CalcClient != null) { CalcClient.Dispose(); } } } } public static class MultiMiddlewareExtensions { public static IApplicationBuilder UseMulti(this IApplicationBuilder app) { return app.UseMiddleware<MultiMiddleware>(); } } } 

Note that the Call method gets an IClientProvider (via DI) that will return another HttpClient object based on some string (this is just for demonstration here). The string may be the name of the provider .... Then we use these clients to call the external apis. This is what I want mock

here is the IClientProvider interface :

  using System.Net.Http; namespace Multi.Web.Api { public interface IClientProvider { HttpClient GetClientFor(string providerName); } } 

Then I created the middleware (test middleware) to mock the request coming from the SUT (this is above).

  using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; using System; using System.Threading.Tasks; namespace Multi.Web.Api.Test.FakeApi { public class FakeExternalApi { private readonly RequestDelegate next; public FakeExternalApi(RequestDelegate next) { this.next = next; } public async Task Invoke(HttpContext context) { //Mocking the calcapi if (context.Request.Host.Value.Equals("www.calcapi.io")) { if (context.Request.Path.Value == "/count") { await context.Response.WriteAsync("1"); } } //Mocking the calendarapi else if (context.Request.Host.Value.Equals("www.calendarapi.io")) { if (context.Request.Path.Value == "/today") { await context.Response.WriteAsync("2015-04-15"); } else if (context.Request.Path.Value == "/yesterday") { await context.Response.WriteAsync("2015-04-14"); } else if (context.Request.Path.Value == "/tomorow") { await context.Response.WriteAsync("2015-04-16"); } } else { throw new Exception("undefined host : " + context.Request.Host.Value); } await next(context); } } public static class FakeExternalApiExtensions { public static IApplicationBuilder UseFakeExternalApi(this IApplicationBuilder app) { return app.UseMiddleware<FakeExternalApi>(); } } } 

here I mock the request coming from two different hosts and listen to a different path. I could also make two intermediate layers, one for each host.

next, I created a TestClientHelper that uses this FakeExternalApi

  using Microsoft.AspNet.TestHost; using Multi.Web.Api.Test.FakeApi; using System; using System.Net.Http; namespace Multi.Web.Api { public class TestClientProvider : IClientProvider, IDisposable { TestServer _fakeCalendarServer; TestServer _fakeCalcServer; public TestClientProvider() { _fakeCalendarServer = TestServer.Create(app => { app.UseFakeExternalApi(); }); _fakeCalcServer = TestServer.Create(app => { app.UseFakeExternalApi(); }); } public HttpClient GetClientFor(string providerName) { if (providerName == "calendar") { return _fakeCalendarServer.CreateClient(); } else if (providerName == "calc") { return _fakeCalcServer.CreateClient(); } else { throw new Exception("Unsupported external api"); } } public void Dispose() { _fakeCalendarServer.Dispose(); _fakeCalcServer.Dispose(); } } } 

This basically returns the correct client for the server we requested.

Now I can create my test methods:

  using System; using System.Net; using System.Threading.Tasks; using Microsoft.AspNet.TestHost; using Microsoft.Framework.DependencyInjection; using Shouldly; using Xunit; using Microsoft.AspNet.Builder; using System.Net.Http; namespace Multi.Web.Api { public class TestServerHelper : IDisposable { public TestServerHelper() { ClientProvider = new TestClientProvider(); ApiServer = TestServer.Create((app) => { app.UseServices(services => { services.AddSingleton<IClientProvider>(s => ClientProvider); }); app.UseMulti(); }); } public TestClientProvider ClientProvider { get; private set; } public TestServer ApiServer { get; private set; } public void Dispose() { ApiServer.Dispose(); ClientProvider.Dispose(); } } public class MultiMiddlewareTest : IClassFixture<TestServerHelper> { TestServerHelper _testServerHelper; public MultiMiddlewareTest(TestServerHelper testServerHelper) { _testServerHelper = testServerHelper; } [Fact] public async Task ShouldReturnToday() { using (HttpClient client = _testServerHelper.ApiServer.CreateClient()) { var response = await client.GetAsync("http://localhost/today"); response.StatusCode.ShouldBe(HttpStatusCode.OK); String content = await response.Content.ReadAsStringAsync(); Assert.Equal(content, "2015-04-15 count is 1"); } } [Fact] public async Task ShouldReturnYesterday() { using (HttpClient client = _testServerHelper.ApiServer.CreateClient()) { var response = await client.GetAsync("http://localhost/yesterday"); response.StatusCode.ShouldBe(HttpStatusCode.OK); String content = await response.Content.ReadAsStringAsync(); Assert.Equal(content, "2015-04-14 count is 1"); } } [Fact] public async Task ShouldReturn404() { using (HttpClient client = _testServerHelper.ApiServer.CreateClient()) { var response = await client.GetAsync("http://localhost/someOtherDay"); response.StatusCode.ShouldBe(HttpStatusCode.NotFound); } } } } 

TestServHelper shuts down Api and ClientProvider , which is a mock implementation here, but in production it will be a real ClientProvider implementation that will return the HttpClient target to real hosts. (a factory)

I do not know if this is the best solution, but it fits my needs ... There is still a problem with Xunit.net for the solution ...

+1
source

All Articles