web-dev-qa-db-ja.com

ユニットテスト用のAPIを介して返されるTask <IActionResult>から値を取得する方法

ASP.NET MVC Core v2.1を使用してAPIを作成しました。私のHttpGetメソッドの1つは次のように設定されています。

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);

コントローラーのアクションにテストするコードは多くなく、ロジックの大部分は、テストがはるかに簡単な別の場所にある分離されたオブジェクトにあることをお勧めします。そうは言っても、まだコントローラーをテストしたい場合は、テストasyncを作成して呼び出しを待つ必要があります。

発生する問題の1つは、BadRequest(...)およびOk(...)を返すことができるため、IActionResultを使用していることです。ただし、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();
}
11
DavidG

返されるタイプを変更せずに、テスト済みのコントローラーを取得できます。
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);
    }
}
7
Fabio

私の評判では、正しい方向に進む@DavidGの答えにコメントすることはできませんので、Task<IActionResult>

@クリストファーJ.レイノルズが指摘したように、actionResult.Valueruntimeで見ることができますが、compilationでは見えません。

そこで、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));
}

確かにこれは改善される可能性がありますが、私はあなたにそれを得る簡単な方法を見せたかっただけです。

役に立てば幸いです。

4

次のようにIActionResultオブジェクトを取得するには、GetConfigurationの呼び出しを待つ必要があります。

var actionResult = await controller.GetConfiguration(12);

これを行うには、テストメソッドのシグネチャも非同期に変更する必要があります。これを変更してください:

public void ConfigurationSearchGetTest()

これに:

public async Task ConfigurationSearchGetTest()
1
Baffour