簡體   English   中英

如何從任務中獲取值<IActionResult>通過用於單元測試的 API 返回

[英]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
    }
}

請注意,我們現在直接返回對象,因為存在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();
}

由於我的聲譽不允許我評論 @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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM