使用C# dynamic关键字获取HttpResponseMessage进行测试的内容

14

在其中一个动作中,我做了类似于这样的事情

public HttpResponseMessage Post([FromBody] Foo foo)
{
    .....
    .....

    var response = 
          Request.CreateResponse(HttpStatusCode.Accepted, new { Token = "SOME_STRING_TOKEN"});
    return response;
}

还有更多像这样返回匿名类型实例并且它们运行良好的方法。

现在,我正在为它编写测试。我有

HttpResponseMessage response = _myController.Post(dummyFoo);

HttpResponseMessage有一个叫做Content的属性,并且还有一个 ReadAsAsync<T>()方法。

我知道如果有一个具体的类型,我可以这样做:

Bar bar = response.Content.ReadAsAsync<Bar>();

但是我该如何访问返回的匿名类型?这可行吗?

我希望能够执行以下操作:

dynamic responseContent = response.Content.ReadAsAsync<object>();
string returnedToken = responseContent.Token;

但是我得到了一个错误,即类型对象的实例没有属性Token。尽管调试器显示responseContent有一个属性Token,但这种情况仍然发生。我理解为什么会出现这种情况,但我想知道是否有一种方法可以访问该属性。

输入图像描述

谢谢


你能分享一下 responseToken 的类型吗?可以使用 ((object)responseContent.GetType()) 进行查看。谢谢。 - Matías Fidemraizer
@MatíasFidemraizer System.Threading.Tasks.Task1[System.Object]` - Professor Chaos
2个回答

16

.ReadAsAsync<T> 是一个异步方法,意味着它不会返回整个反序列化对象,而是返回一个 Task<T> 以处理整个异步任务的继续。

你有两个选择:

1. 异步模式。

在封闭方法中使用 async 关键字(例如:public async void A()),然后以这种方式进行异步调用:

dynamic responseContent = await response.Content.ReadAsAsync<object>();
string returnedToken = responseContent.Token;

2. 定期任务 API

或者您可以使用任务 API:

response.Content.ReadAsAsync<object>().ContinueWith(task => {
   // The Task.Result property holds the whole deserialized object
   string returnedToken = ((dynamic)task.Result).Token;
});

由你决定!

更新

在你发布整个屏幕截图之前,没有人知道你是在调用 task.Wait 以等待异步结果。但我会保持我的回答,因为它可能会帮助更多的访问者 :)

正如我在自己的答案评论中建议的那样,你应该尝试将其反序列化为 ExpandoObject。ASP.NET WebAPI 使用 JSON.NET 作为其底层 JSON 序列化器。也就是说,它可以处理匿名 JavaScript 对象反序列化到可扩展对象。


我已经附上了一张图片,显示了异常和匿名类型以及我感兴趣的属性。我不知道是否可以将单元测试方法设置为异步,所以我会尝试选项2并告诉你结果。 - Professor Chaos
@ProfessorChaos 如果你在调用异步方法,就不应该模拟同步返回值。你需要模仿实际行为。请尝试使用反序列化 ExpandoObject 而不是 object - Matías Fidemraizer
@ProfessorChaos 嗯,现在我明白发生了什么。请再次检查我的答案:您没有使用我试图向您展示的任何选项。请检查我的答案中的传入更新。 - Matías Fidemraizer
使用ExpandoObject起作用了,那就是我所缺少的。如果您可以编辑您的答案,我会接受它。 - Professor Chaos
@ProfessorChaos 已完成,希望您能解决问题 ;) - Matías Fidemraizer
我对C#的异步概念不熟悉。我删除了Wait(),因为我以同步方式调用它(没有await),所以没有任何区别。感谢您对ExpandoObject的帮助! - Professor Chaos

0

您也可以使用类似以下代码来使用单元测试测试HttpResponseMessage。

这对我很有效。

希望这能帮到您。

[TestClass]
    public class UnitTest
    {
        [TestMethod]
        public void Post_Test()
        {
           //Arrange
           var contoller = new PostController();  //the contoller which you want to test
           controller.Request = new HttpRequestMessage();
           controller.Configuration = new HttpConfiguration();

           // Act
           var response = controller.Post(new Number { PhNumber = 9866190822 });
           // Number is the Model name and PhNumber is the Model Property for which you want to write the unit test

           //Assert
           var request = response.StatusCode;
           Assert.AreEqual("Accepted", request.ToString());

        }
    }

同样地,根据需要在断言中更改HttpResponseMessage。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接