[英]How to get the Values from a Task<IActionResult> returned through an API for Unit Testing
我使用 ASP.NET MVC Core v2.1 创建了一个 API。 我的HttpGet
方法之一设置如下:
public async Task<IActionResult> GetConfiguration([FromRoute] int? id)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
..... // Some code here
return Ok(configuration);
}
catch (Exception ex)
{
... // Some code here
}
}
在进行单元测试时,我可以检查 Ok 是响应,但我确实需要查看配置的值。 我似乎无法让它与以下一起工作:
[TestMethod]
public void ConfigurationSearchGetTest()
{
var context = GetContextWithData();
var controller = new ConfigurationSearchController(context);
var items = context.Configurations.Count();
var actionResult = controller.GetConfiguration(12);
Assert.IsTrue(true);
context.Dispose();
}
在运行时,我可以检查actionResult
是否具有某些我无法编码的值。 有什么我做错了吗? 还是我只是在想这个错误? 我希望能够做到:
Assert.AreEqual(12, actionResult.Values.ConfigurationId);
您可以在不更改返回类型的情况下获得经过测试的控制器。
IActionResult
是所有其他人的基本类型。
将结果转换为预期类型并将返回值与预期进行比较。
由于您正在测试异步方法,因此也要使测试方法异步。
[TestMethod]
public async Task ConfigurationSearchGetTest()
{
using (var context = GetContextWithData())
{
var controller = new ConfigurationSearchController(context);
var items = context.Configurations.Count();
var actionResult = await controller.GetConfiguration(12);
var okResult = actionResult as OkObjectResult;
var actualConfiguration = okResult.Value as Configuration;
// Now you can compare with expected values
actualConfuguration.Should().BeEquivalentTo(expected);
}
}
好的做法是建议您在控制器操作中没有大量代码需要测试,并且大部分逻辑位于其他更容易测试的解耦对象中。 话虽如此,如果您仍然想测试您的控制器,那么您需要使您的测试async
并等待调用。
您将遇到的问题之一是您正在使用IActionResult
因为它允许您返回BadRequest(...)
和Ok(...)
。 但是,由于您使用的是 ASP.NET MVC Core 2.1,您可能希望开始使用新的ActionResult<T>
类型。 这应该有助于您的测试,因为您现在可以直接访问强类型返回值。 例如:
//Assuming your return type is `Configuration`
public async Task<ActionResult<Configuration>> GetConfiguration([FromRoute] int? id)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
..... // Some code here
// Note we are now returning the object directly, there is an implicit conversion
// done for you
return configuration;
}
catch (Exception ex)
{
... // Some code here
}
}
请注意,我们现在直接返回对象,因为存在从Foo
到ActionResult<Foo>
的隐式转换
现在你的测试看起来像这样:
[TestMethod]
public async Task ConfigurationSearchGetTest()
{
var context = GetContextWithData();
var controller = new ConfigurationSearchController(context);
var items = context.Configurations.Count();
// We now await the call
var actionResult = await controller.GetConfiguration(12);
// And the value we want is now a property of the return
var configuration = actionResult.Value;
Assert.IsTrue(true);
context.Dispose();
}
由于我的声誉不允许我评论 @DavidG 的答案是正确的,我将放一个关于如何在Task<IActionResult>
获取值的示例。
正如@ Christopher J. Reynolds 指出的那样, actionResult.Value
可以在运行时看到,但不能在编译时看到。
因此,我将展示一个获取Values
的基本测试:
[TestMethod]
public async Task Get_ReturnsAnArea()
{
// Arrange
string areaId = "SomeArea";
Area expectedArea = new Area() { ObjectId = areaId, AreaNameEn = "TestArea" };
var restClient = new Mock<IRestClient>();
restClient.Setup(client => client.GetAsync<Area>(It.IsAny<string>(), false)).ReturnsAsync(expectedArea);
var controller = new AreasController(restClient.Object);
//// Act
// We now await the call
IActionResult actionResult = await controller.Get(areaId);
// We cast it to the expected response type
OkObjectResult okResult = actionResult as OkObjectResult;
// Assert
Assert.IsNotNull(okResult);
Assert.AreEqual(200, okResult.StatusCode);
Assert.AreEqual(expectedArea, okResult.Value);
// We cast Value to the expected type
Area actualArea = okResult.Value as Area;
Assert.IsTrue(expectedArea.AreaNameEn.Equals(actualArea.AreaNameEn));
}
当然,这可以改进,但我只是想向您展示一个简单的方法来获得它。
我希望它有帮助。
您需要等待对 GetConfiguration 的调用以获取 IActionResult 对象,如下所示:
var actionResult = await controller.GetConfiguration(12);
为此,您还需要将测试方法的签名更改为异步。 所以改变这个:
public void ConfigurationSearchGetTest()
对此:
public async Task ConfigurationSearchGetTest()
如果您需要快速解决方案,请使用 JsonConvert.SerializeObject() ,然后使用 JsonConvert.DeserializeObject() 然后您将获得带有值的对象。
[TestMethod]
public async Task ConfigurationSearchGetTest()
{
using (var context = GetContextWithData())
{
var controller = new ConfigurationSearchController(context);
var items = context.Configurations.Count();
var actionResult = await controller.GetConfiguration(12);
var okResult = actionResult as OkObjectResult;
var actualConfiguration = okResult.Value ;
//
//IMPORTANT ONLY BELOW two lines need.
//
var actualConfigurationJStr=JsonConvert.SerializeObject( okResult.Value );
var hereObjectWithStrongType=JsonConvert.DeserializeObject<Configuration>(actualConfigurationJStr);
// Now you can compare with expected values
actualConfuguration.Should().BeEquivalentTo(expected);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.