Lars Michael
Lars Michael

Reputation: 693

ASP.NET Web API routing unit test - controller actions not detected

I am trying to unit test the routings in my ASP.NET Web API 2 controllers. I am strictly following the recipe 11-6 in the newly released book ASP.NET Web Api 2 Recipes. Here is my controller:

[RoutePrefix("api/account")]
public class AccountController : ApiController
{
    private AccountService _accountService;

    public AccountController(AccountService service)
    {
        _accountService = service;
    }

    [Route("{id}")]
    public IHttpActionResult Get(string id)
    {
        return Ok(_accountService.Get(id));
    }

    [Route("all")]
    public IHttpActionResult GetAll()
    {
        return Ok(_accountService.GetAll());
    }
}

And here are my unit tests (xunit):

public class AccountRoutingTest
{
    readonly HttpConfiguration _config;

    public AccountRoutingTest()
    {
        _config = new HttpConfiguration();
        _config.MapHttpAttributeRoutes();
        _config.EnsureInitialized();
    }

    [Theory]
    [InlineData("http://acme.com/api/account/john")]
    public void GetRoutingIsOk(string url)
    {
        var request = new HttpRequestMessage(HttpMethod.Get, url);
        var routeTester = new RouteContext(_config, request);

        Assert.Equal(typeof(AccountController), routeTester.ControllerType);
        Assert.True(routeTester.VerifyMatchedAction(Reflection.GetMethodInfo((AccountController c) => c.Get(""))));
    }

    [Theory]
    [InlineData("http://acme.com/api/account/all")]
    public void GetAllRoutingIsOk(string url)
    {
        var request = new HttpRequestMessage(HttpMethod.Get, url);
        var routeTester = new RouteContext(_config, request);

        Assert.Equal(typeof(AccountController), routeTester.ControllerType);
        Assert.True(routeTester.VerifyMatchedAction(Reflection.GetMethodInfo((AccountController c) => c.GetAll())));
    }
}

The first unit test passes but the second one fails. I have isolated the problem to be in the RouteContext helper class in the following line, where the GetActionMapping method only detects the Get(id) action - not the GetAll():

_actionMappings = actionSelector.GetActionMapping(descriptor)[request.Method.ToString()];

I have tried to explicitly decorate the GetAll() action method with the [HttpGet] attribute and to switch from attribute routing to centralized routing - but without success. I am running out of ideas. Why is the GetAll() action - and all other actions except the Get(id) action - not detected by the GetActionMapping method?

The routing is fine when tested from a browser or Fiddler.

Upvotes: 1

Views: 361

Answers (1)

Filip W
Filip W

Reputation: 27187

Looks like a tiny bug :)

Change

_actionMappings = actionSelector.GetActionMapping(descriptor)[request.Method.ToString()];

to:

_actionMappings = actionSelector.GetActionMapping(descriptor).
SelectMany(x => x).Where(x => x.SupportedHttpMethods.Contains(request.Method));

Upvotes: 2

Related Questions