在我的集成测试中,发送到/api/schoolyears url 的对象 schoolyearCreateRequest 在传递给 Post([FromBody] SchoolyearCreateRequest request)
操作参数时仅包含空值。
但是当我使用小提琴手时:
http://localhost:6320/api/schoolyears
Content-Type: application/json
Request Body:
{ SchoolyearDto:
{ Id: 10 }
}
然后它有效,学年Dto不为空。
我的集成测试有什么问题?
var schoolyearCreateRequest = new SchoolyearCreateRequest
{
SchoolyearDto = new SchoolyearDto(),
SchoolclassCodeDtos = new List<SchoolclassCodeDTO>(),
TimeTablesWeekAddedWeekA = new List<TimeTableDTO>(),
TimeTablesWeekAddedWeekAB = new List<TimeTableDTO>()
};
// Arrange
const string url = "api/schoolyears/";
var request = new HttpRequestMessage(HttpMethod.Post, _server.BaseAddress + url);
request.Content = new ObjectContent<SchoolyearCreateRequest>(schoolyearCreateRequest,new JsonMediaTypeFormatter());
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// Act
var response = _client.PostAsync(_server.BaseAddress + url, request, new JsonMediaTypeFormatter(), new CancellationToken()).Result;
// Assert
Assert.That(response.StatusCode == HttpStatusCode.Created);
更新:
我现在在我的集成测试中也让它工作:
替换以下行:
request.Content = new ObjectContent<SchoolyearCreateRequest>(schoolyearCreateRequest,new JsonMediaTypeFormatter());
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
用这一行:
var postData = new StringContent(JsonConvert.SerializeObject(schoolyearCreateRequest), Encoding.UTF8, "application/json");
为什么我必须自己序列化数据?为什么几乎没有人在 Web API 集成测试中采用这种方法?我读过的所有博客都显示了ObjectContent的用法?
你可以在下面的帖子中看看我的回答:
如何使用 HttpServer 在测试中练习格式化程序?
另外,你可以看看我的博客文章,这是很久以前写的,但仍然相关:
http://blogs.msdn.com/b/kiranchalla/archive/2012/05/06/in-memory-client-amp-host-and-integration-testing-of-your-web-api-service.aspx
更新:
由于对此似乎存在混淆,以下是内存中测试的完整示例。它有点粗糙,但仍然应该给你一个想法。
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using WebApplication251.Models;
namespace WebApplication251.Tests.Controllers
{
[TestClass]
public class PeopleControllerTest
{
string baseAddress = "http://dummyhost/";
[TestMethod]
public void PostTest()
{
HttpConfiguration config = new HttpConfiguration();
// use the configuration that the web application has defined
WebApiConfig.Register(config);
HttpServer server = new HttpServer(config);
//create a client with a handler which makes sure to exercise the formatters
HttpClient client = new HttpClient(new InMemoryHttpContentSerializationHandler(server));
Person p = new Person() { Name = "John" };
using (HttpResponseMessage response = client.PostAsJsonAsync<Person>(baseAddress + "api/people", p).Result)
{
Assert.IsNotNull(response.Content);
Assert.IsNotNull(response.Content.Headers.ContentType);
Assert.AreEqual<string>("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
Person recPerson = response.Content.ReadAsAsync<Person>().Result;
Assert.AreEqual(p.Name, recPerson.Name);
}
}
}
public class InMemoryHttpContentSerializationHandler : DelegatingHandler
{
public InMemoryHttpContentSerializationHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Content = await ConvertToStreamContentAsync(request.Content);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Content = await ConvertToStreamContentAsync(response.Content);
return response;
}
private async Task<StreamContent> ConvertToStreamContentAsync(HttpContent originalContent)
{
if (originalContent == null)
{
return null;
}
StreamContent streamContent = originalContent as StreamContent;
if (streamContent != null)
{
return streamContent;
}
MemoryStream ms = new MemoryStream();
await originalContent.CopyToAsync(ms);
// Reset the stream position back to 0 as in the previous CopyToAsync() call,
// a formatter for example, could have made the position to be at the end
ms.Position = 0;
streamContent = new StreamContent(ms);
// copy headers from the original content
foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
{
streamContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
return streamContent;
}
}
}