单元测试自定义IHttpActionResult

3
我正在尝试创建一个自定义的IHttpActionResult类型,用于在Web API 2中返回HTML内容而不是JSON。我遇到的问题是如何对返回新的ActionResult类型的ApiController进行单元测试。许多示例都告诉你将其转换为OkNegotiatedContentResult,然后读取其中的content属性,但这在我的情况下似乎无效。当我调试测试时,ExecuteAsync中的代码块似乎从未被调用过。我需要在我的单元测试中明确执行此操作吗?非常感谢您的帮助。
这是我的ActionResult的样子:
public class HtmlActionResult : IHttpActionResult
{
    String _html;
    public HtmlActionResult(string html)
    {
        _html = html;
    }

    public Task<System.Net.Http.HttpResponseMessage> ExecuteAsync(System.Threading.CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StringContent(_html );
        response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/html");
        return Task.FromResult(response);
    }
}

这是我的ApiController。

public class HomeController : ApiController
{
    public IHttpActionResult Get(string page)
    {
        return new HtmlActionResult("<html></html>");
    }
}

这是我的测试方法

[TestMethod]
public async Task Get()
{
    //Arrenge
    HomeController controller = new HomeController();

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

    //Assert
    //Assert.IsNotNull(result.Content);
}

1
我可能在这里说错了,但是单独测试HtmlActionResult可能值得一试?然后再单独测试控制器。这可能涉及到大量的配置设置(可能是IIS),如果是这种情况,那么这将不会是一个单元测试。 - Spock
为什么您首先要有一个返回HTML的ApiController? - abatishchev
4个回答

4
使用 Fluent Assertions
IHttpActionResult result = await controller.Get()

HtmlActionResult htmlActionResult = result.Should()
                                          .BeOfType<HtmlActionResult>()
                                          .Which; // <-- the key feature
                                          // or .And

您可以嵌套断言,这意味着您可以在一个断言语句中编写多个条件来检查该语句的有效性。
IHttpActionResult result = await controller.Get()

result.Should().BeOfType<HtmlActionResult>()
      .Which.Content.Should().Be(expected);

或者正如@Spock建议的那样,将事物分开测试:

  • Get() 返回实际上是 HtmlActionResult 的 IHttpActionResult
  • HtmlActionResult 如何独立于 Get() 工作

2

您没有等待控制器操作完成 - 您应该将测试更改为以下内容(未经尝试):

public async Task Get()
{
    // Arrange
    HomeController controller = new HomeController();

    // Act
    IHttpActionResult result = await controller.Get();

    // Assert
    Assert.IsNotNull(result.Content);
}

2
假设您正在使用 WebAPI 版本 2,可以在ASP.NET 网站上找到一份非常好的指南,介绍如何对控制器进行单元测试。
我曾经遇到类似的情况,并有些不确定是否应该使控制器方法返回Tasks而不是IHttpActionResults——我认为后者更加简洁。但是我成功地将上述链接中的“测试返回 HttpResponseMessage 的操作”部分的代码适配到我的单元测试中,并能够如预期般运行。
以下是我情境的简化概述:
public class XyzController : ApiController
{
    private readonly IDbContext _dbContext;

    public XyzController(IDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpGet]
    [Route("this-is-optional")]
    public IHttpActionResult Get(<optional-params-here>)
    {
        // Do work
        ...

        // My data is an array of objects
        return Ok(data);
    }
}

[TestFixture]
public class XyzControllerTest
{
    [Test]
    public void Get_ReturnsSuccessfully()
    {
        // Arrange
        IDbContext testContext = MockDbContext.Create();
        ...
        // Populate textContext here
        ...
        XyzController xyzController = new XyzController(testContext)
        {
            // These are required or exceptions will be thrown
            Request = new HttpRequestMessage();
            Configuration = new HttpConfiguration()
        };            
        ...

        // Act
        var response = xyzController.Get(<params-if-required>).ExecuteAsync(CancellationToken.None);

        // Assert
        Assert.IsNotNull(response);
        Assert.IsTrue(response.IsCompleted);
        Assert.AreEqual(HttpStatusCode.OK, response.Result.StatusCode);

        // Assertions on returned data
        MyModel[] models;
        Assert.IsTrue(response.Result.TryGetContentValue<MyModel[]>(out models));
        Assert.AreEqual(5, model.Count());

        Assert.AreEqual(1, model.First().Id);
        ...
    }
}

1

试试这个:

[TestMethod]
public void Get()
{
    //Arrenge
    var controller = new HomeController();

    //Act
    var result = controller.Get().Result as HtmlActionResult;

    //Assert
    Assert.IsNotNull(result);
}

注意,您的测试可以是void,您不必等待Get方法,可以使用.Result来运行任务。
另外,我将结果转换为HtmlActionResult,如果结果是不同的ActionResult,如OkResult、NotFoundResult等,则最终结果将为Null。
希望这有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接