【问题标题】:Asserting JsonResult Containing Anonymous Type断言包含匿名类型的 JsonResult
【发布时间】:2013-06-01 18:55:20
【问题描述】:

我试图在我的一个控制器中对返回 JsonResult 的方法进行单元测试。令我惊讶的是,以下代码不起作用:

[HttpPost]
public JsonResult Test() {
    return Json(new {Id = 123});
}

这是我测试它的方式(另请注意,测试代码驻留在另一个程序集中):

// Act
dynamic jsonResult = testController.Test().Data;

// Assert
Assert.AreEqual(123, jsonResult.Id);

Assert 抛出异常:

“object”不包含“Id”的定义

我已经使用以下方法解决了它:

[HttpPost]
public JsonResult Test() {
   dynamic data = new ExpandoObject();
   data.Id = 123;
   return Json(data);
}

我试图理解为什么第一个不起作用?它似乎也适用于除了匿名类型之外的任何东西。

【问题讨论】:

  • 我用匿名类型尝试了你的代码,对我来说效果很好。不知道您为什么会收到该错误。
  • 当您打印出jsonResult.GetType() 时会得到什么? (错误表明它认为它是 object 类型而不是 <>f__AnonymousType0 类型,这是我所期望的)
  • 类型确实是对象。我希望它自己工作,不知道为什么我会得到这些结果。
  • 这个简短的 sn-p 对我来说很好用:var result = new JsonResult { Data = new { Id = "foo" } }; dynamic foo = result.Data; Console.WriteLine(foo.Id); 它对你有用吗?
  • @KirkWoll,谢谢你的帮助,伙计,匿名似乎不能在其他库中使用(查看 LukLed 的答案),我不知道,要多读一些。

标签: c# asp.net-mvc json unit-testing


【解决方案1】:

需要明确的是,您遇到的具体问题是 C# 动态不适用于非公共成员。这是设计使然,大概是为了阻止这种事情。由于正如 LukLed 所说,匿名类型仅在同一个程序集中是公共的(或者更准确地说,匿名类型只是标记为internal,而不是public),你遇到了这个障碍。

可能最干净的解决方案是您使用InternalsVisibleTo。它允许您命名另一个可以访问其非公共成员的程序集。将其用于测试是其存在的主要原因之一。在您的示例中,您将在主项目的 AssemblyInfo.cs 中放置以下行:

[assembly: InternalsVisibleTo("AssemblyNameOfYourTestProject")]

一旦你这样做了,错误就会消失(我自己试过了)。

或者,您可以只使用蛮力反射:

Assert.AreEqual(123, jsonResult.GetType().GetProperty("Id").GetValue(jsonResult, null));

【讨论】:

  • 你能解释一下最后一个选项吗?
  • 你能澄清你的问题吗?您是否想知道一般的反思,还是想知道它如何应用于这个问题/答案?
  • 一般反射
  • @Ani,在这种情况下,我认为这是一个太大的话题,无法在 cmets 中讨论,而且我相信这样的阐述会分散 OP 的原始问题。这里的基本要点是,您可以从Type 获取PropertyInfo,并使用它可以获取或设置属性的值,而不管类型是否为内部使用GetValue 方法。跨度>
【解决方案2】:

阅读了这里的回复,然后再看更远的地方,我发现2009 msdn blog post 再次采用了不同的方法。但是.. 在 cmets 中,Kieran 提供了一个非常简单且非常优雅的解决方案...使用 .ToString()

在你原来的情况下:

[HttpPost]
public JsonResult Test()
{
    return Json(new {Id = 123});
}

您可以通过以下方式进行测试:

var jsonResult = controller.Test();
Assert.AreEqual("{Id = 123}", jsonResult.Data.ToString());

我更喜欢这个解决方案:

  • 避免更改原始代码(InternalsVisibleToExpandoObject),
  • 避免使用 MvcContribRhinoMocks(这两个都没有问题,但为什么要添加只是为了能够测试JsonResult?),并且,
  • 避免使用 Reflection(增加了测试的复杂性)。

【讨论】:

  • 这依赖于 ToString 实现不改变,- 1
【解决方案3】:

匿名类型是内部的,因此您不能将它们暴露给另一个库,即带有测试的库。如果您将测试代码与控制器放在同一个库中,它将起作用。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-23
  • 2013-03-25
  • 2021-12-04
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多