使用具有匿名类型的 OkNegotiatedContentResult 对 IHttpActionResult 进行单元测试
Posted
技术标签:
【中文标题】使用具有匿名类型的 OkNegotiatedContentResult 对 IHttpActionResult 进行单元测试【英文标题】:Unit testing IHttpActionResult with OkNegotiatedContentResult having anonymous types 【发布时间】:2021-11-20 08:12:41 【问题描述】:我正在使用 MS Test 对我的 Web API 控制器进行单元测试。
下面是我的 Web API 控制器方法,返回类型:
public IHttpActionResult MethodName() //Code logic
return Ok(new Data = result, Total = (result.Count() > 0 ? result.First().TotalCount : 0) );
在上面的代码sn-p中:
-
数据类型为 IEnumerable
现在测试上面的 API 方法返回类型是我尝试过的:
[TestMethod]
public void TestMethodName()
var result = controller.MethodName();
//Below line is having issue and thus the contentResult is null
var contentResult = result as OkNegotiatedContentResult<List<ViewModelName>>;
将 Int 添加到 OkNegotiatedContentResult 会引发错误,因为它仅排除单个参数
以下是 API 的实际返回类型:
System.Web.Http.Results.OkNegotiatedContentResultf__AnonymousType0
我应该如何转换结果以便我可以将其内容用于 Assert ?
提前谢谢你。 代码示例表示赞赏。
【问题讨论】:
看看我这里给的答案***.com/a/42718643/5233410 @NKosi 看起来不错,但我没有异步任务您遇到的问题是您的OkNegotiatedContentResult<T>
具有T
的匿名类型。当您像使用new Date = .., Total =..
一样创建临时类型时,编译器会为您生成一个匿名类型。按照设计,匿名类型的名称永远不能在 C# 代码中使用,但仅在编译后的 JIT 代码中有效。
这就是为什么将您的结果转换为OkNegotiatedContentResult<List<ViewModelName>>
将不起作用的原因,因为T
不是List<ViewModelName>
,而是anonymoustype<System.Collections.Generic.List<ViewModel'>, int>>
。
在我看来,最好的选择不是使用匿名类型,而是创建一个具有您正在寻找的两个属性的实际类,并在您的控制器和测试中使用该类型。
public class MyData
public List<ViewModel> Data get; set;
public int Total get; set;
如果您不想更改代码,可以使用反射或动态关键字,如下所示:
dynamic contentResult = (dynamic)result.Content;
var data = contentResult.Data
【讨论】:
我明白你的回答。仍然没有任何方法可以在不更改其实现的情况下对其进行测试@WouterdeKort @Jimesh 我已经用另一种使用动态的解决方案更新了答案 有一个构建错误指出:“IHttpActionResult 不包含 Content 的定义,并且找不到接受 IHttpActionResult 类型的第一个参数的异常方法内容” 仅供参考:我已经添加了 Microsoft.CSharp。动态的dll @Jimesh 将您的操作方法的返回类型更改为OkNegotiatedContentResult
不是替代方法,因为将返回类型从 IHttpActionResult 更改为 OkNegotiatedContentResult 需要传递 这是一个解决方案,乍一看可能有点麻烦。
所以,首先确保我们收到了OkNegotiatedContentResult
//Act
var actionResult = controller.MethodName();
//Assert - OkNegotiated result
var resultType = actionResult.GetType().GetGenericTypeDefinition();
Assert.AreEqual(resultType.GetGenericTypeDefinition(), typeof(OkNegotiatedContentResult<>));
然后确保匿名类型定义了Data
属性
免责声明:以下代码在运行时无法检索Content
//Assert - Anonymous type
dynamic content = ((dynamic)actionResult).Content;
Assert.IsTrue(content.GetType().GetProperty("Data") != null);
最后确保Data
属性是一个集合
//Assert - Data property
Assert.IsInstanceOfType(content.Data, typeof(IEnumerable<ViewModelName>));
var data = (IEnumerable<ViewModelName>)content.Data;
【讨论】:
感谢您的努力。主要问题是“var content = result.Content”。错误:“IHttpActionResult 不包含 Content 的定义,不包含扩展方法 Content,但可以找到 IHttpActionResult 类型的第一个参数” 在此之前,虽然 Assert.IsInstanceOfType 我得到:“Assert.IsInstanceOfType 失败。预期类型:2[System.Collections.Generic.List
1 [ViewModel],System.Int32]]>。"actionResult
变量来存储controller.MethodName
调用的结果。然后我在将其转换为OkNegotiatedContentResult
后使用了result
。在您的测试代码中,您的result
确实是IHttpActinResult
,而在我的版本中,它应该是OkNegotiatedContentResult
,它确实具有Content
属性。
我的sn-p代码和你的一样。获取:Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll 中出现“Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException”类型的异常,但未在用户代码中处理附加信息:Assert.IsInstanceOfType 失败。预期类型:2[System.Collections.Generic.List
1[ViewModel],System.Int32]]>。以上是关于使用具有匿名类型的 OkNegotiatedContentResult 对 IHttpActionResult 进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章
XML 和 XSD 验证失败:元素同时具有“类型”属性和“匿名类型”子项