断言包含匿名类型的JsonResult
我试图在我的一个控制器中unit testing一个方法,返回一个JsonResult。 令我惊讶的是,以下代码不起作用:
[HttpPost] public JsonResult Test() { return Json(new {Id = 123}); }
这是我测试它的方式(还要注意测试代码驻留在另一个程序集中):
// Act dynamic jsonResult = testController.Test().Data; // Assert Assert.AreEqual(123, jsonResult.Id);
Assert
引发exception:
‘object’不包含’Id’的定义
我已经通过使用以下方法解决了它:
[HttpPost] public JsonResult Test() { dynamic data = new ExpandoObject(); data.Id = 123; return Json(data); }
我试图理解为什么不是第一个工作? 它似乎也基本上可以用于任何匿名类型。
需要说明的是,您遇到的具体问题是C#dynamic不能与非公共成员一起使用。 这是设计的,大概是为了阻止那种事情。 因为正如LukLed所说,匿名类型只在同一个程序集中公开(或者更准确地说,匿名类型只是标记为internal
,而不是public
),您正在遇到这个障碍。
可能最干净的解决方案是使用InternalsVisibleTo
。 它允许您命名另一个可以访问其非公共成员的程序集。 将其用于测试是其存在的主要原因之一。 在您的示例中,您将在主项目的AssemblyInfo.cs中放置以下行:
[assembly: InternalsVisibleTo("AssemblyNameOfYourTestProject")]
一旦你这样做,错误将消失(我只是自己尝试过)。
或者,您可以使用powershellreflection:
Assert.AreEqual(123, jsonResult.GetType().GetProperty("Id").GetValue(jsonResult, null));
在阅读了这里的回复,然后在更远的地方看了一下,我发现了一个2009 msdn博客文章 ,再次采用了不同的方法。 但是……在评论中, Kieran是一个非常简单而且非常优雅的解决方案……使用.ToString()
。
在你原来的情况下:
[HttpPost] public JsonResult Test() { return Json(new {Id = 123}); }
你可以这样做:
var jsonResult = controller.Test(); Assert.AreEqual("{Id = 123}", jsonResult.Data.ToString());
我更喜欢这个解决方案:
- 避免更改原始代码(
InternalsVisibleTo
,ExpandoObject
), - 避免使用MvcContrib和RhinoMocks (这些都没有问题,但为什么只是为了能够测试
JsonResult
而添加?),以及 - 避免使用Reflection (增加了测试的复杂性)。
匿名类型是内部的,因此您不能将它们暴露给另一个库,即带有测试的库。 如果您将测试代码放在与控制器相同的库中,它将起作用。
- 我应该永远不会调用HostingEnvironment.UnregisterObject吗?
- ASP.NET MVC授权具有许多角色的用户
- MVC 5:我应该从IdentityUser类inheritance我的用户吗?
- MiniProfiler没有出现在asp.net MVC上
- 没有IIS的主机MVC Web应用程序
- 使用未分配的变量?
- 未找到路径’/ Account / Login’的控制器或未实现IController
- 如何在ASP.NET MVC 6中继续使用ModelState和RedirectToAction?
- ASP.NET MVC StackOverflowException从布局中的xml加载动态菜单