Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
654 views
in Technique[技术] by (71.8m points)

c# - Mock HttpRequest in ASP.NET Core Controller

I'm building a Web API in ASP.NET Core, and I want to unit test the controllers.

I inject an interface for data access, that I can easily mock. But the controller has to check the headers in the Request for a token, and that Request doesn't seem to exist when I simply instantiate the controller myself, and it is also get-only, so I can't even manually set it. I found lots of examples to mock an ApiController, but that isn't .NET core. Also many tutorials and examples of how to unit test .net core controllers, but none actually used the HttpRequest.

I built an MCVE to demonstrate this:

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

    }
}    

I'm using Moq and MSTest in my test project, and inject a mocked IAccessor. How do I inject the Request, or initialize it with the controller? I guess my last resort would be reflection, but I really want to avoid that.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When creating an instance of the controller under test, make sure to assign a HttpContext that contains the required dependencies for the test to be exercised to completion.

You could try mocking a HttpContext and providing that to the controller or just use DefaultHttpContext provided by the framework

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

//...

The above assumes you already know how to mock the controller dependencies like IAccessor and was meant to demonstrate how to provide framework specific dependencies needed for the test.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...