Тестирование/интеграция Тестирование веб-API с помощью HttpClient в Visual Studio 2013
Мне нелегко пытаться протестировать мой контроллер API с помощью Visual Studio 2013. Мое одно решение имеет проект веб-API и проект тестирования. В моем тестовом проекте у меня есть Unit Test с этим:
[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;
}
}
Я продолжаю получать 404. Я попытался запустить свой API с одним экземпляром Visual Studio (IIS Express) и попытаться отладить этот Unit Test в другом экземпляре. Но не повезло. Я проверил, что могу поместить этот URL в браузер (когда одна Visual Studio отлаживается), и я вижу ответ JSON. Но я не могу понять, как заставить его работать с моими Unit Test и HttpClient
. Я пытался найти примеры в Интернете, но, похоже, не нашел их. Может кто-нибудь помочь?
ОБНОВЛЕНИЕ 1:
Я попытался добавить маршрут, но ничего не произошло.
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]
Вот мой API-контроллер
[HttpGet]
[Route("api/product/hello/")]
public IHttpActionResult Hello()
{
return Ok();
}
ОБНОВЛЕНИЕ Разрешение:
Я смог заставить его работать, если я обновляю HttpClient
без объекта HttpServer
. Тем не менее, мне все равно нужно иметь два экземпляра VS. 1 запустил мой код API, а другой - для запуска Unit Test.
Вот рабочий метод.
[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);
}
}
Кто-нибудь знает, почему он не работает с HttpServer
и a HttpConfiguration
, переданными в HttpClient
? Я видел много примеров, которые используют это.
Ответы
Ответ 1
Ссылка на следующую статью, которую я смог сделать...
Тестирование интеграции ASP.NET Web API с хостингом в памяти
работая с HttpServer
и a HttpConfiguration
, переданными в HttpClient
. В следующем примере я создал простой ApiController
, который использует маршрутизацию атрибутов. Я настроил маршрут HttpConfiguration
для сопоставления атрибутов, а затем передал его новому HttpServer
. Затем HttpClient
может использовать настроенный сервер для выполнения тестовых вызовов интеграции на тестовом сервере.
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();
}
}
}
Не нужно было использовать другой экземпляр VS для интеграции теста контроллера.
Кроме того, была проведена следующая упрощенная версия теста
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);
}
}
В вашем случае вам нужно убедиться, что вы правильно настроили сервер, чтобы он соответствовал вашей настройке api. Это означало бы, что вам необходимо зарегистрировать маршруты api с помощью объекта HttpConfiguration
.
var config = new HttpConfiguration();
//configure web api
WebApiConfig.Register(config);
//...other code removed for brevity
Ответ 2
Выполнение с использованием тестов GET/POST, которые я использовал -
public static HttpResponseMessage ConfigureAndAct(string relativeApiUrl, HttpMethod httpMethodType, string bodyForPostMethod, int userid)
{
var uri = new Uri(string.Concat("http://localhost:10022", relativeApiUrl)); // Todo:Find free port at runtime
// var identity = new GenericIdentity(userid.ToString()); // If Needed
// Thread.CurrentPrincipal = new GenericPrincipal(identity, null); // If Needed
HttpResponseMessage response;
using (HttpConfiguration config = new HttpConfiguration())
{
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
// WebApiConfig.Register(config); // If Needed
// FilterConfig.RegisterGlobalFilters(GlobalConfiguration.Configuration.Filters); // If Needed
// config.Services.Replace(typeof(IHttpControllerSelector), new VersionControllerSelector(config)); // If Needed
using (HttpRequestMessage request = new HttpRequestMessage()
{
Content = new StringContent(bodyForPostMethod, Encoding.UTF8, "application/json"),
RequestUri = uri,
Method = httpMethodType,
})
{
// var creds = new CommonSetupRepository().GetUserNameAndPassword(userid); // If Needed
// var toekn = Pearl.Utilities.Security.CryptionService.Encrypt<RijndaelManaged>(String.Format("{0}:{1}", creds.UserName, creds.Password)); // If Needed
// request.Headers.Add("rb-api-version", "0.0.1"); // If Needed
// request.Headers.Add("rb-token", toekn); // If Needed
using (var server = new HttpServer(config))
{
using (var client = new HttpClient(server))
{
response = client.SendAsync(request, CancellationToken.None).Result;
}
}
}
}
return response;
}
// Test GET
-----------
//Act
var response = ConfigureWebApiForTest.ConfigureAndAct(uriToTest, HttpMethod.Get, string.Empty, userId);
var result = response.Content.ReadAsAsync<Activity>().Result;
//Assert
Assert.IsTrue(response.StatusCode == HttpStatusCode.OK);
Assert.IsNotNull(result);
Assert.AreEqual(expectedUrl, result.SomeUrl);
// Test POST
------------
// Act
HttpResponseMessage response = ConfigureWebApiForTest.ConfigureAndAct(uriToTest, HttpMethod.Post, body, userId);
//Assert
Assert.IsTrue(response.StatusCode == HttpStatusCode.OK);