How to unit test whether a Core MVC controller action calls ControllerBase.Problem()

前端 未结 2 1445
你的背包
你的背包 2021-01-12 16:26

We have a controller that derives from ControllerBase with an action like this:

public async Task Get(int id)
{
  try
  {
           


        
相关标签:
2条回答
  • 2021-01-12 17:04

    In your tests, if you first create a ControllerContext, then ProblemDetails should be created as expected while executing controller code.

    ...
    MyController controller;
    
    [Setup]
    public void Setup()
    {
        controller = new MyController();
        controller.ControllerContext = new ControllerContext
        {
            HttpContext = new DefaultHttpContext
            {
                // add other mocks or fakes 
            }
        };
    }
    ...
    
    0 讨论(0)
  • 2021-01-12 17:26

    The null exception is because of a missing ProblemDetailsFactory

    In this case the controller needs to be able to create ProblemDetails instance via

    [NonAction]
    public virtual ObjectResult Problem(
        string detail = null,
        string instance = null,
        int? statusCode = null,
        string title = null,
        string type = null)
    {
        var problemDetails = ProblemDetailsFactory.CreateProblemDetails(
            HttpContext,
            statusCode: statusCode ?? 500,
            title: title,
            type: type,
            detail: detail,
            instance: instance);
    
        return new ObjectResult(problemDetails)
        {
            StatusCode = problemDetails.Status
        };
    }
    

    Source

    ProblemDetailsFactory is a settable property

    public ProblemDetailsFactory ProblemDetailsFactory
    {
        get
        {
            if (_problemDetailsFactory == null)
            {
                _problemDetailsFactory = HttpContext?.RequestServices?.GetRequiredService<ProblemDetailsFactory>();
            }
    
            return _problemDetailsFactory;
        }
        set
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }
    
            _problemDetailsFactory = value;
        }
    }
    

    Source

    that could be mocked and populated when testing in isolation.

    [TestMethod]
    public async Task GetCallsProblemOnInvalidId() {
        //Arrange
        var problemDetails = new ProblemDetails() {
            //...populate as needed
        };
        var mock = new Mock<ProblemDetailsFactory>();
        mock
            .Setup(_ => _.CreateProblemDetails(
                It.IsAny<HttpContext>(),
                It.IsAny<int?>(),
                It.IsAny<string>(),
                It.IsAny<string>(),
                It.IsAny<string>(),
                It.IsAny<string>())
            )
            .Returns(problemDetails)
            .Verifyable();
    
        var sut = new MyController(...);
        sut.ProblemDetailsFactory = mock.Object;
    
        //...
    
        //Act
        var result = await sut.Get(someInvalidId);
    
        //Assert
        mock.Verify();//verify setup(s) invoked as expected
    
        //...other assertions
    }
    
    0 讨论(0)
提交回复
热议问题