2

I have an ApiController and would like to test it with unit tests including the routing.

An example:

[RoutePrefix("prefix")]
public class Controller : ApiController
{
    [HttpGet]
    [Route("{id1}")]
    public int Add(int id1, [FromUri] int id2)
    {
        return id1 + id2;
    }
}

I would now like to test this method. I see, that I can test it like an ordinary method. But I would also like to test it with the translation of the URL to the method parameters.

Basically I would like to have an automatic test where I call a URL like prefix/10?id2=5 and get a result of 15. Is this somehow possible?

2
  • you are wanting to test your routes. It's a common thing to want to test, there are several guides on how to do it. Commented Nov 4, 2016 at 13:26
  • research TestServer in Web API. This would be considered integration testing. Commented Nov 4, 2016 at 13:27

4 Answers 4

3

I wrote a little helper class for in-memory integration testing that can be called as part of the test suit.

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);
    }
}

And would then use it like this

[TestMethod]
public async Task HttpClient_Should_Get_OKStatus_From_InMemory_Hosting() {

    using (var server = new HttpTestServer()) {

        MyWebAPiProjectNamespace.WebApiConfig.Configure(server.Configuration);

        var client = server.CreateClient();

        string url = "http://localhost/prefix/10?id2=5";
        var expected = 15;

        var request = new HttpRequestMessage {
            RequestUri = new Uri(url),
            Method = HttpMethod.Get
        };

        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        using (var response = await client.SendAsync(request)) {
            Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
            var result = await response.Content.ReadAsAsync<int>();
            Assert.AreEqual(expected, result);
        }
    }
}

This will configure an in-memory test server that the test can make calls to using its httpclient. It is in essence an end-to-end integration test.

Sign up to request clarification or add additional context in comments.

6 Comments

I do not see, where this is connected to my Controller class.
If you look at the url you would see that it is trying to test the route in your controller as well as what the response would be. Which is what you wanted in your question. Was I mistaken?
I think you have the answer I am looking for. I have troubles getting it to run. I can't find the WebApiConfig. Also the IntegrationTest Attribute ... I think I dont need it?
You don't need it. that's a custom attribute I had in my test project. will update answer. as for the WebApiConfig. look for a Startup folder in your web api project. it should be there. just make sure you have the correct namespace in the test.
I don't see it. There is a static Startup class, with one Method ConfigureApp(). There is no folder Startup. The whole project is an azure service fabric web api -- if it matters. I can't get the line MyWebAPiProjectNamespace.WebApiConfig.Configure(server.Configuration); to work. I've tried the namespace of my Controller class and the namespace of the Startup class.
|
2
  1. Create an OWIN StartUp class using Microsoft ASP.NET Web API 2.2 OWIN package:

    public class Startup
    { 
        public void Configuration(IAppBuilder builder)
        {
            var config = new HttpConfiguration();
    
            builder.UseWebApi(config);
    
            config.MapHttpAttributeRoutes();
            config.EnsureInitialized();
        }
    }
    
  2. Use Microsoft ASP.NET Web API 2.2 Self Host package in your tests (used NUnit for example):

    [Test]
    [TestCase(10, 5, 15)]
    [TestCase(1, 2, 3)]
    // add your test cases
    public async Task AdditionTests(int a, int b, int result) 
    {
        // Arrange
        var address = "http://localhost:5050";
    
        using (WebApp.Start<Startup>(address))
        {
            var client = new HttpClient();
    
            var requestUri = $"{address}/prefix/{a}?id2={b}";
    
            // Act
            var response = await client.GetAsync(requestUri);
    
            // Assert
            Assert.IsTrue(await response.Content.ReadAsAsync<int>() == result);
        }
    }
    

Comments

1

That is an integration test, not a unit test. If you wanted to automate this you would have to have a tool that would launch/host your web api and then execute requests against it.

If you wanted to keep it as a unit test though you could validate the attributes on the class and the method and check the values.

var type = typeof(Controller);
var attributeRoutePrefix = type.GetCustomAttribute(typeof(RoutePrefixAttribute)) as RoutePrefixAttribute;
Assert.IsNotNull(attributeRoutePrefix);
Assert.AreEqual("prefix", attributeRoutePrefix.Prefix);

var methodAttribute = type.GetMethod(nameof(Controller.Add)).GetCustomAttribute(typeof(RouteAttribute)) as RouteAttribute;
Assert.IsNotNull(methodAttribute);
Assert.AreEqual("id1", methodAttribute.Template);

Comments

1

Its possible by using postman or fiddler to test with url param..

7 Comments

@stuartd, the moment you start testing using URLs, you're no longer unit testing. It's called functional/acceptance/integration tests (depending on when you're coming from) and you're not limited to a single language. I honestly don't understand the downvotes as this is a legimate testing method via external tools.
Its not possible with unit test but another option to test the method.
@stuartd Before giving negative vote please think that how it is possible to test the url in unit test without external tools.
Well, you can @Satheshkumar.. You just need a framework or something, that can create requests on demand and enables you to evaluate the results. PHP has codeception (for instance), but I'm pretty sure C# has something similar too. But yeah, using postman/filder/... is a very valid way of doing it as well.
@walther Fair enough. But I would say the question isn't how to test a URL, so much as how to unit test the defined routings, which is certianly possible without external tools
|

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.