Steven Edouard

Developer Advocate. Tech Enthusiast. Life Enthusiast.

NAVIGATION - SEARCH

How to test Asp.NET Web Api's with Visual Studio Test Explorer

So myself and my buddy Jamie decided to quickly start working on a web app powered by Asp.NET MVC4 and Web API. I'm working on most of the back end and I really wanted to have a good Test-Driven-Development environment in Visual Studio (2013). Naturally I wanted to use the VS Test Explorer window to mimick the client calls to each API to validate my dev work.

After searching around a bit I found a few handy blog posts like this one from one of my colleagues at Microsoft. This post is great because it shows you how to test your WebApi completley in-process without having to use the networking stack. However I like to use the in-box Visual Studio tools rather than xUnit that this blog had.

To give you a background on my setup I have a web app called GiftMe. Here's my Visual Studio solution setup:

Giftme.sln

     >GiftMe.csproj (The ASP.NET web api)

     >GIftMe.Tests (A unit test framework library)

 

So I have my Web API controller in the GIftMe.csproj project which looks something like this:

public class AuthenticationController : ApiController
{
     // POST /api/authentication/authenticate
     [ActionName("Authenticate")]
     public async Task<IHttpActionResult> PostAuthentication(User user)
     {
          //Actual implementation hidden
          return Ok();
     }
}

 

And then afterwards I naturally added a new unit test library, GiftMe.Tests.csproj. Afterwards you have to add the required dependency libraries:

 

GiftMe <solution project reference>

System.Web

System.Web.Http

System.Web.Http.WebHost

(You probably want to add Json.NET while you're at it from the Nuget package manager if you are sending JSON to your web api).

 

Then I added the test:

[TestMethod]
        public void Authenticate()
        {

            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            HttpServer server = new HttpServer(config);
            
            
            using (HttpMessageInvoker client = new HttpMessageInvoker(server))
            {
                using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/authentication/authenticate"))
                {
                    string user = JsonConvert.SerializeObject(new User()
                    {
                        FacebookId = "112512525",
                        AccessToken = SecureCloudConfigurationManager.GetSetting("GiftMe.Facebook.AccessToken"),
                        Email = "someemailaddress@outlook.com"
                    });
                    request.Content = new StringContent(user);
                    request.Content.Headers.ContentType.MediaType = "application/json";

                    Trace.WriteLine("Sending: " + user + " to api/authentication/authenticate");
                    using (HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result)
                    {
                        //verify status code
                        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
                    }
                    
                }
            };
        }



To my surprise, I kept getting HTTP404 errors back from the request. After a while it I was wondering how Web API 'magically' fond your controller to route http messages. It turns out that it looks at all loaded modules in the process for anything that extends the ApiController type. It also turned out that if you make no reference to the actual controller, the .NET runtime loader will never load the DLL with the Web API controllers (even though you reference GiftMe.dll) unless you actually use something in that DLL.

How do you fix this? Well for this example if you just reference the type AuthenticationController anywhere you'll force the runtime to load GiftMe.dll allowing the in-proc sever to find your Web API. I recommend putting this in the class initializer for the test library like so:

public sealed class ControllerTests
    {
        AuthenticationController m_AuthController;
 
        [ClassInitialize]
        public static void Initialize(TestContext context)
        {     
               //force runtime to load GiftMe.dll for http handlers
               m_AuthController = new AuthenticationController();
        }
 
//...begin test methods


And viola! Your controller should be able to handle the request from the in-proc server and you have a nice, integrated test-driven-development environment for all of your web apis organized in a sane way.

Comments (2) -

Wohh exactly what I was looking for, thanks for putting up.

Reply

No problem hope this helps!

Reply

Add comment

biuquote
  • Comment
  • Preview
Loading