单元测试自定义IHttpactionResult

时间:2014-11-14 13:28:34

标签: c# unit-testing asp.net-web-api

我正在尝试在web api 2中创建一个自定义的IHttpActionResult类型,它将以HTML而不是json的形式返回内容。我正在努力的是如何对返回我的新ActionResult类型的ApiController进行单元测试。许多显示如何对ApiController进行单元测试的示例告诉您将其强制转换为OkNegotiatedContentResult,然后从中读取内容属性,但这似乎不适用于我的情况。当我调试测试时,似乎永远不会调用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);
}

4 个答案:

答案 0 :(得分: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()返回IHttpActionResult,实际上是HtmlActionResult
  • HtmlActionResult如何独立于Get()
  • 工作

答案 1 :(得分:2)

您不是在等待控制器操作完成 - 您应该将测试更改为(这是未经验证的):

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

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

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

答案 2 :(得分:1)

试试这个:

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

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

    //Assert
    Assert.IsNotNull(result);
}

请注意,您的测试可能无效,并且您不必等待Get方法,您可以使用.Result来运行任务。

此外,我将结果转换为HtmlActionResult,如果结果是一个不同的ActionResult,如OkResult,或NotFoundResult,等等,结果将为Null。

希望有所帮助。

答案 3 :(得分:1)

假设您正在使用WebAPI版本2,那么有关如何在The ASP.NET Site上单元测试控制器的非常好的指南。

我遇到了类似的情况,并且让我的控制器方法返回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);
        ...
    }
}