1

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.

1 Answer 1

2

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));
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Filip. Anyway for Apress to fix it in your book too?

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.