Search code examples
c#unit-testingasp.net-web-api-routingasp.net-web-api2

Testing Controller routing, how to post data using HttpRequestMessage


I'm trying to test routing to my Controller's methods. I've got the following unit test:

[Test]
public void POST_PlaylistItem_Should_route_to_PlaylistItemController_Create_method()
{
    var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/PlaylistItem/");

    var config = new HttpConfiguration();

    WebApiConfig.Register(config);
    var route = Helpers.RouteRequest(config, request);

    route.Controller.Should().Be<PlaylistItemController>();
    route.Action.Should().Be("Create");
}

I need to be able to POST content with the message so that my controller can make a decision between the two following signatures:

[HttpPost]
public PlaylistItemDto Create(PlaylistItemDto playlistItemDto)

[HttpPost]
public IEnumerable<PlaylistItemDto> CreateMultiple(List<PlaylistItemDto> playlistItemDtos)

I was looking through some resources and I found an example for doing it using async + HttpClient, http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client#PostingResource, but I wasn't keen on overcomplicating my example with unfamiliar technology until I had the basics working. Using the HttpClient I wasn't able to easily send a message to the controller / it was acting as if a server isn't running.


Solution

  • Alright, I got it figured out. Note that I haven't converted to Attribute-based routing which is preferable, but this serves as a good starting example:

    Goal is to test that these two method signatures don't conflict / confuse Web API:

    [HttpPost]
    public PlaylistItemDto Create(PlaylistItemDto playlistItemDto)
    
    [HttpPost]
    public IEnumerable<PlaylistItemDto> CreateMultiple(List<PlaylistItemDto> playlistItemDtos)
    

    In my WebApiConfig class:

    config.Routes.MapHttpRoute(
        name: "Create",
        routeTemplate: "PlaylistItem",
        defaults: new
        {
            controller = "PlaylistItem",
            action = "Create"
        }
    );
    
    config.Routes.MapHttpRoute(
        name: "CreateMultiple",
        routeTemplate: "PlaylistItem/CreateMultiple",
        defaults: new
            {
                controller = "PlaylistItem",
                action = "CreateMultiple"
            }
    );
    

    This says that anything with just an action name of PlaylistItem will be routed to the Create action. Anything that is PlaylistItem/CreateMultiple will be routed to the CreateMultiple action.

    Then, to check to see if this works:

    [Test]
    public void POST_PlaylistItem_Should_route_to_PlaylistItemController_Create_method()
    { 
        // setups
        var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/PlaylistItem/");
    
        var config = new HttpConfiguration();
    
        // act
        WebApiConfig.Register(config);
        var route = Helpers.RouteRequest(config, request);
    
        // asserts
        route.Controller.Should().Be<PlaylistItemController>();
        route.Action.Should().Be("Create");
    }
    
    [Test]
    public void POST_CreateMultiple_PlaylistItem_Should_route_to_PlaylistItemController_CreateMultiple_method()
    {
        // setups
        var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/PlaylistItem/CreateMultiple");
    
        var config = new HttpConfiguration();
    
        // act
        WebApiConfig.Register(config);
        var route = Helpers.RouteRequest(config, request);
    
        // asserts
        route.Controller.Should().Be<PlaylistItemController>();
        route.Action.Should().Be("CreateMultiple");
    }
    

    where RouteRequest comes from Testing route configuration in ASP.NET WebApi