Integration Testing - How to hit endpoints using Microsoft.Owin.Testing.TestServer?

Viewed 957

I have setup a basic Web API project to test writing integration tests, with the below setup

Startup:

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(WebApiTest.Startup))]

namespace WebApiTest
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            WebApiConfig.Register(new System.Web.Http.HttpConfiguration());
        }
    }
}

And the following controller:

using System.Web.Http;

namespace WebApiTest.Controllers
{
    public class TestController : ApiController
    {
        public IHttpActionResult Post()
        {
            return Ok("Hello, world!");
        }
    }
}

For my Tests project I am using NUnit for my testing, and have two classes: an abstract BaseTest class, and a ControllerTests class which contains one test with the intention of sending a web request out to the above TestController's GET Action method:

BaseTest:

using Microsoft.Owin.Testing;
using NUnit.Framework;
using System;
using System.Net.Http;

namespace WebApiTest.Tests
{
    public abstract class BaseTest : IDisposable
    {
        protected const string _url = "http://localhost/";
        protected TestServer _server;

        public void Dispose()
        {
            _server.Dispose();
        }

        [SetUp]
        public void SetUp()
        {
            _server = TestServer.Create<Startup>();
        }

        protected HttpRequestMessage CreateRequest(string url, string 
contentType, HttpMethod method)
        {
            HttpRequestMessage request = new HttpRequestMessage
            {
                RequestUri = new Uri(_url + url),
                Method = method
            };
            request.Headers.Accept.Add(new 
System.Net.Http.Headers.MediaTypeWithQualityHeaderValue(contentType));
            return request;
        }
    }
}

ControllerTests:

using FluentAssertions;
using NUnit.Framework;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace WebApiTest.Tests
{
    [TestFixture]
    public class ControllerTests : BaseTest
    {
        [Test]
        public async Task Test1()
        {
            HttpRequestMessage request = CreateRequest("test", "application/json", HttpMethod.Post);
            HttpResponseMessage response = await _server.HttpClient.SendAsync(request);
            response.StatusCode.Should().Be(HttpStatusCode.OK);
        }
    }
}

The problem I am running into is that I'm not able to reach my endpoint with the call await _server.HttpClient.SendAsync(request); as I always get a 404: Not Found response.

I'm not entirely sure what I'm doing wrong, whether it be something that's not being setup property or Api routes that aren't being mapped.

update: Here is my WebApiConfig.Register() method for reference:

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}
2 Answers

The web API was not configured correctly so the routes are not known to it

If you are self-hosting with OWIN, create a new HttpConfiguration instance. Perform any configuration on this instance, and then pass the instance to the Owin.UseWebApi extension method.

public class Startup {
    public void Configuration(IAppBuilder app) {
        var config = new System.Web.Http.HttpConfiguration();
        WebApiConfig.Register(config);
        app.UseWebApi(config); //<-- THIS WAS MISSING 
    }
}

Reference Configuring Web API with OWIN Self-Hosting

It appears that my Tests project was not aware of all the DI my API was doing at startup, since all the code for that was not contained within my Startup's Configuration method.

In a older version of my code I had the below two lines in my Configuration method:

app.UseNinjectMiddleware(NinjectWebCommon.CreateKernel);
app.UseNinjectWebApi(configuration);

Back when I deleted these two lines out of the Configuration method I did not understand why they were there. If the dependencies are bound at startup, it would seem that these two lines are just redundant.

While that is true, in the case of referencing this Startup class from my Tests project, I need both of those so my Test project can handle dependencies correctly.

Related