将复杂类型发布到 Web API 操作仅适用于提琴手,但在集成测试中无效



在我的集成测试中,发送到/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;
        }
    }
}

相关内容

最新更新