web-dev-qa-db-ja.com

ASP.NET CoreコントローラーでのHttpRequestのモック

ASP.NET CoreでWeb APIを構築していますが、コントローラーの単体テストを行います。

簡単にモックできるデータアクセス用のインターフェイスを挿入します。しかし、コントローラーはトークンのリクエストのヘッダーをチェックする必要があり、コントローラーを自分でインスタンス化するだけではそのリクエストは存在しないように見えます。また、取得専用であるため、手動で設定することもできません。 ApiControllerをモックする多くの例を見つけましたが、それは.NETコアではありません。また、多くのチュートリアルと.netコアコントローラーの単体テスト方法の例がありますが、実際にHttpRequestを使用したものはありません。

これを実証するためにMCVEを作成しました。

[Produces("application/json")]
[Route("api/Players")]
public class PlayersController : Controller
{
    private IAccessor accessor;

    public PlayersController(IAccessor ac = null):base()
    {
        accessor = ac ?? AccessorFactory.GetAccessor();
    }

    /// <summary>
    /// Get all players. Must be logged in.
    /// </summary>
    /// <returns>Ok or Unauthorized.</returns>
    [HttpGet]
    public IActionResult Get()
    {
        Player client = accessor.GetLoggedInPlayer(Request.Headers["token"]); // NRE here because Request is null
        if (client == null) return Unauthorized();
        return Ok(accessor.GetAllPlayers());

    }
}    

テストプロジェクトでMoqとMSTestを使用し、モックされたIAccessorを挿入します。リクエストを注入する方法、またはコントローラーで初期化する方法私の最後の手段は反射だと思いますが、私は本当にそれを避けたいです。

13
Squirrelkiller

テスト対象のコントローラーのインスタンスを作成するときは、テストが完了するまでに必要な依存関係を含むHttpContextを必ず割り当ててください。

HttpContextをモックしてコントローラーに提供するか、フレームワークが提供するDefaultHttpContextを使用してみてください。

//Arrange
var mockedAccessor = new Mock<IAccessor>();
//...setup mockedAccessor behavior

//...

var httpContext = new DefaultHttpContext(); // or mock a `HttpContext`
httpContext.Request.Headers["token"] = "fake_token_here"; //Set header
 //Controller needs a controller context 
var controllerContext = new ControllerContext() {
    HttpContext = httpContext,
};
//assign context to controller
var controller = new PlayersController (mockedAccessor.Object){
    ControllerContext = controllerContext,
};

//Act
var result = controller.Get();

//...

上記は、IAccessorのようなコントローラーの依存関係を模擬する方法を既に知っていることを前提としており、テストに必要なフレームワーク固有の依存関係を提供する方法を示すことを目的としています。

18
Nkosi