duyn9uyen duyn9uyen -4 years ago 236
C# Question

Unit Testing / Integration Testing Web API with HttpClient in Visual Studio 2013

I am having a hard time trying to test my API controller with Visual Studio 2013. My one solution has a Web API Project and a Test project. In my test project, I have a Unit Test with this:

[TestMethod]
public void GetProduct()
{
HttpConfiguration config = new HttpConfiguration();
HttpServer _server = new HttpServer(config);

var client = new HttpClient(_server);

var request = new HttpRequestMessage
{
RequestUri = new Uri("http://localhost:50892/api/product/hello"),
Method = HttpMethod.Get
};

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

using (var response = client.SendAsync(request).Result)
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);

var test = response.Content.ReadAsAsync<CollectionListDTO>().Result;
}
}


I keep getting a 404. I have tried running my API with one instance of Visual Studio (IIS Express), and trying to debug this Unit Test in another instance. But no luck. I have verified that I can put this URL in a browser (when one Visual Studio is debugging) and I see my JSON response. But I can't figure out how to get it to work with my unit test and
HttpClient
. I have tried to find examples online but can't seem to find one. Can someone help?

UPDATE 1:
I tried adding in a route but nothing happened.

HttpConfiguration config = new HttpConfiguration();

// Added this line
config.Routes.MapHttpRoute(name: "Default", routeTemplate: "api/product/hello/");

HttpServer _server = new HttpServer(config);

var client = new HttpClient(_server);

[...rest of code is the same]


Here is my API Controller

[HttpGet]
[Route("api/product/hello/")]
public IHttpActionResult Hello()
{
return Ok();
}


UPDATE Resolution:
I was able to get it to work if I new up
HttpClient
without a
HttpServer
object. I would still need to have two instances of VS running though. 1 running my API code and another to run the Unit Test.

Here is a working method.

[TestMethod]
public void Works()
{
var client = new HttpClient(); // no HttpServer

var request = new HttpRequestMessage
{
RequestUri = new Uri("http://localhost:50892/api/product/hello"),
Method = HttpMethod.Get
};

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

using (var response = client.SendAsync(request).Result)
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
}


Anyone know why it doesn't work with a
HttpServer
and a
HttpConfiguration
passed into
HttpClient
? I have seen many examples that use this.

Answer Source

Referencing the following article I was able to do...

ASP.NET Web API integration testing with in-memory hosting

by working with a HttpServer and a HttpConfiguration passed into HttpClient. In the following example I created a simple ApiController that uses attribute routing. I configured the HttpConfiguration to map attribute routes and then passed it to the new HttpServer. The HttpClient can then use the configured server to make integration test calls to the test server.

public partial class MiscUnitTests {
    [TestClass]
    public class HttpClientIntegrationTests : MiscUnitTests {

        [TestMethod]
        public async Task HttpClient_Should_Get_OKStatus_From_Products_Using_InMemory_Hosting() {

            var config = new HttpConfiguration();
            //configure web api
            config.MapHttpAttributeRoutes();

            using (var server = new HttpServer(config)) {

                var client = new HttpClient(server);

                string url = "http://localhost/api/product/hello/";

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

    public class ProductController : ApiController {
        [HttpGet]
        [Route("api/product/hello/")]
        public IHttpActionResult Hello() {
            return Ok();
        }
    }
}

There was no need to have another instance of VS running in order to integration test the controller.

The following simplified version of the test worked as well

var config = new HttpConfiguration();
//configure web api
config.MapHttpAttributeRoutes();

using (var server = new HttpServer(config)) {

    var client = new HttpClient(server);

    string url = "http://localhost/api/product/hello/";

    using (var response = await client.GetAsync(url)) {
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
    }
}

In your case you need to make sure that you are configuring the server properly to match your web api setup. This would mean that you have to register your api routes with the HttpConfiguration object.

var config = new HttpConfiguration();
//configure web api
WebApiConfig.Register(config);
//...other code removed for brevity
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download