web-dev-qa-db-ja.com

ActionResult <T>でユニットテストを行う方法

次のようなxUnitテストがあります。

[Fact]
public async void GetLocationsCountAsync_WhenCalled_ReturnsLocationsCount()
{
    _locationsService.Setup(s => s.GetLocationsCountAsync("123")).ReturnsAsync(10);
    var controller = new LocationsController(_locationsService.Object, null)
    {
        ControllerContext = { HttpContext = SetupHttpContext().Object }
    };
    var actionResult = await controller.GetLocationsCountAsync();
    actionResult.Value.Should().Be(10);
    VerifyAll();
}

ソースは

/// <summary>
/// Get the current number of locations for a user.
/// </summary>
/// <returns>A <see cref="int"></see>.</returns>
/// <response code="200">The current number of locations.</response>
[HttpGet]
[Route("count")]
public async Task<ActionResult<int>> GetLocationsCountAsync()
{
    return Ok(await _locations.GetLocationsCountAsync(User.APropertyOfTheUser()));
}

結果の値がnullであるため、テストが失敗しますが、ActionResult.Result.Value(内部プロパティ)予期される解決済みの値が含まれます。

次のデバッガの画面キャプチャを参照してください。 enter image description here

ユニットテストに入力するactionResult.Valueを取得するにはどうすればよいですか?

14

実行時には、暗黙的な変換のため、テスト中の元のコードは引き続き機能します。

しかし、提供されたデバッガーイメージに基づいて、テストが結果の間違ったプロパティでアサートしていたように見えます。

したがって、テスト中のメソッドを変更すると、テストに合格することができますが、いずれかの方法でライブで実行すると機能します。

_ActioResult<TValue>_には、それを使用するアクションから何が返されるかに応じて設定される2つのプロパティがあります。

_/// <summary>
/// Gets the <see cref="ActionResult"/>.
/// </summary>
public ActionResult Result { get; }

/// <summary>
/// Gets the value.
/// </summary>
public TValue Value { get; }
_

ソース

そのため、コントローラアクションがOk()を使用して返された場合、暗黙的な変換によってアクション結果の_ActionResult<int>.Result_プロパティが設定されます。

_public static implicit operator ActionResult<TValue>(ActionResult result)
{
    return new ActionResult<TValue>(result);
}
_

しかし、テストはValueプロパティ(OPの画像を参照)をアサートしていましたが、この場合は設定されていませんでした。

テストを満たすためにテスト中のコードを変更する必要がなく、Resultプロパティにアクセスしてその値に対してアサーションを作成できます

_[Fact]
public async Task GetLocationsCountAsync_WhenCalled_ReturnsLocationsCount() {
    //Arrange
    _locationsService
        .Setup(_ => _.GetLocationsCountAsync(It.IsAny<string>()))
        .ReturnsAsync(10);
    var controller = new LocationsController(_locationsService.Object, null) {
        ControllerContext = { HttpContext = SetupHttpContext().Object }
    };

    //Act
    var actionResult = await controller.GetLocationsCountAsync();

    //Assert
    var result = actionResult.Result as OkObjectResult;
    result.Should().NotBeNull();
    result.Value.Should().Be(10);

    VerifyAll();
}
_
6
Nkosi

問題はそれをOkでラップすることです。オブジェクト自体を返す場合、Valueは正しく入力されます。

ドキュメント内のMicrosoftの例 を見ると、NotFoundのようなデフォルト以外の応答に対してのみコントローラーメソッドを使用しています。

[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<Product> GetById(int id)
{
    if (!_repository.TryGetProduct(id, out var product))
    {
        return NotFound();
    }

    return product;
}
0
Eric Eskildsen