如何从通过API进行单元测试返回的Task <IActionResult>中获取值

Chr*_*lds 11 c# asp.net-core-mvc .net-core

我使用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
    }
}
Run Code Online (Sandbox Code Playgroud)

单元测试时,我可以检查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();
}
Run Code Online (Sandbox Code Playgroud)

在运行时,我可以检查是否actionResult有某些我无法编​​码的值.有什么我做错了吗?或者我只是想到这个错误?我希望能够做到:

Assert.AreEqual(12, actionResult.Values.ConfigurationId);
Run Code Online (Sandbox Code Playgroud)

Dav*_*idG 12

好的做法是建议您在控制器操作中没有很多代码来测试,而大量逻辑在其他地方的解耦对象中更容易测试.话虽如此,如果您仍想测试您的控制器,那么您需要进行测试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
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,现在我们直接返回对象,因为是从隐式转换FooActionResult<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();
}
Run Code Online (Sandbox Code Playgroud)

  • 因此,这似乎部分起作用,但是检查actionResult.Value为null。actionResult.Result.Value.ConfigurationId可以在运行时看到,但是我无法为其编程,因为它不存在。 (5认同)

Fab*_*bio 10

您可以在不更改返回类型的情况下获得经过测试的控制器。
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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Seb*_*nes 8

由于我的声誉不允许我评论 @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));
}
Run Code Online (Sandbox Code Playgroud)

当然,这可以改进,但我只是想向您展示一个简单的方法来获得它。

我希望它有帮助。


Baf*_*our 1

您需要等待对 GetConfiguration 的调用才能获取 IActionResult 对象,如下所示:

var actionResult = await controller.GetConfiguration(12);
Run Code Online (Sandbox Code Playgroud)

为此,您还需要将测试方法的签名更改为异步。所以改变这个:

public void ConfigurationSearchGetTest()
Run Code Online (Sandbox Code Playgroud)

对此:

public async Task ConfigurationSearchGetTest()
Run Code Online (Sandbox Code Playgroud)