2

When I curl to the /test route it works fine, however the test below 404's when trying to hit the in memory server on the same route.

When inspecting _client and _config appear to be ok - although I am not sure how to confirm that my in memory server is functioning correctly.

Does anybody know how I can get my in memory web server to map it's routes correctly so my test method can reach it?

namespace Robo.Tests.Controllers
{

    [TestClass]
    public class IntegrationTests
    {
        private HttpMessageInvoker _client;
        private HttpConfiguration _config = new HttpConfiguration();

        [TestInitialize]
        public void SetupTest()
        {
            _config.MapHttpAttributeRoutes();
            _config.EnsureInitialized();

            var server = new HttpServer(_config);
            _client = new HttpMessageInvoker(server);
        }

        [TestMethod]
        public async Task Test()
        {
            var result = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "http://localhost/test"), CancellationToken.None);
        }
    }
}

and controller in case you are interested

namespace Robo.Controllers
{
    //[ValidationActionFilter]
    public class CVController : ApiController
    {

        [HttpGet]
        [Route("test")]
        public async Task<IHttpActionResult> test()
        {
            return Ok();
        }
    }
}
9
  • I believe in-memory test server listens to localhost. so it would be http://localhost/test/test assuming that the route was {controller}/{action} Commented Oct 21, 2016 at 11:40
  • just tried changing to localhost and still 404ing Commented Oct 21, 2016 at 11:44
  • Is the controller and test in the same assembly? Include the controller class definition. Commented Oct 21, 2016 at 11:44
  • both of them are now in the exact same namespace and it is still 404ing Commented Oct 21, 2016 at 11:50
  • same namespace and same assembly mean different things. update code for controller with class definition. Commented Oct 21, 2016 at 11:52

1 Answer 1

2

For in-memory server testing The following utility class was created. It basically wraps the setup functionality in the example shown.

internal interface IHttpTestServer : IDisposable {
    HttpConfiguration Configuration { get; }
    HttpClient CreateClient();
}

internal class HttpTestServer : IHttpTestServer {
    HttpServer httpServer;

    public HttpTestServer(HttpConfiguration configuration = null) {
        httpServer = new HttpServer(configuration ?? new HttpConfiguration());
    }

    public HttpConfiguration Configuration {
        get { return httpServer.Configuration; }
    }

    public HttpClient CreateClient() {
        var client = new HttpClient(httpServer);
        return client;
    }

    public void Dispose() {
        if (httpServer != null) {
            httpServer.Dispose();
            httpServer = null;
        }
    }

    public static IHttpTestServer Create(HttpConfiguration configuration = null) {
        return new HttpTestServer(configuration);
    }
}

The following test was crafted to demonstrate the use of in memory server using OP

[TestClass]
public class IntegrationTests {

    [TestMethod]
    public async Task Test() {


        using (var server = HttpTestServer.Create()) {
            //Arrange
            var config = server.Configuration;
            config.MapHttpAttributeRoutes();
            config.EnsureInitialized();

            var client = server.CreateClient();
            var url = "http://localhost/test";
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var expected = System.Net.HttpStatusCode.OK;

            //Act
            var result = await client.SendAsync(request, CancellationToken.None);

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(expected, result.StatusCode);
        }

    }

    public class CVController : ApiController {
        [HttpGet]
        [Route("test")]
        public async Task<IHttpActionResult> test() {
            return Ok();
        }
    }
}

Test passes.

The thing about this example is that the test and controller exist in same assembly so map attribute scans the assembly it was called in and found API controller with attribute routes. If controller lived in another project then the web API config of that project should be called on the HttpConfiguration to properly configure web API.

UPDATE

The test project and web api project should be two separate projects. That said, The web project should have a WebApiConfig.cs file with a static WebApiConfig.Register class and method. That method takes a HttpConfiguration parameter. The test should use that method to configure the api for in memory calls.

[TestClass]
public class IntegrationTests {

    [TestMethod]
    public async Task Test() {


        using (var server = HttpTestServer.Create()) {
            //Arrange
            var config = server.Configuration;
            //Config server
            MyWebApiNamespace.WebApiConfig.Register(config);

            var client = server.CreateClient();
            var url = "http://localhost/test";
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            var expected = System.Net.HttpStatusCode.OK;

            //Act
            var result = await client.SendAsync(request, CancellationToken.None);

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(expected, result.StatusCode);
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Ok thank you are you able to elaborate on what you meant by "If controller lived in another project then the web API config of that project should be called on the HttpConfiguration to properly configure web API." I think that is the exact problem because when I debug my server there is only one route there (/)
Using your example worked by the way providing that I have the controller in the same project - since it will sit in a seperate project how should I be calling the web api config on my httpconfiguration?
Thanks for all the effort it is all working now - great answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.