【问题标题】:Unit Testing Async Controller: Exception on Url.Link()单元测试异步控制器:Url.Link() 上的异常
【发布时间】:2016-07-19 18:21:55
【问题描述】:

我想对异步控制器进行单元测试。我以前做过很多次,但从未调用Url.Link()方法来生成位置标头。

这是我的演示代码。

控制器

public class DemoController : ApiController
{
    [HttpPost]
    public async Task<IHttpActionResult> DemoRequestPost(string someRequest)
    {
        // do something await ...
        var id = 1;
        // generate url for location header (here the problem occurrs)
        var url = Url.Link("DemoRequestGet", new {id = id});
        return Created(url, id);
    }

    [HttpGet]
    [Route("demo/{id}", Name = "DemoRequestGet")]
    public async Task<IHttpActionResult> DemoRequestGet(int id)
    {
        // return something
        return Ok();
    }
}

测试

[TestFixture]
public class DemoControllerTests
{
    [Test]
    public async Task CreateFromDraftShouldSucceed()
    {
        // Arrange
        var request = "Hello World";
        var controller = new DemoController();
        var httpConfiguration = new HttpConfiguration();
        // ensure attribte routing is setup
        httpConfiguration.MapHttpAttributeRoutes();
        httpConfiguration.EnsureInitialized();
        controller.Configuration = httpConfiguration;
        // Act
        var result = await controller.DemoRequestPost(request);
        // Assert
        Assert.AreEqual(result, 1);
    }
}

我收到了

在 NUnit.Framework.Internal.ExceptionHelper.Rethrow(异常异常) 在 NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(对象调用结果) 在 NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext context)

【问题讨论】:

  • 你应该await 结果。试试var result = await controller.DemoRequestPost(request);
  • 对不起,这是我的示例代码中的错误。如果我等待结果,也会发生同样的异常。
  • 抛出的异常是什么,异常的消息是什么?还是 NUnit 没有报告完整的异常信息。如果是这样,那是一个错误,请在github.com/nunit/nunit/issues 报告它。如果您没有收到异常,请尝试使用 try/catch 来捕获异常并在调试器中检查它。希望这会告诉您失败的原因。
  • Nunit 不报告异常。测试只是失败了,甚至调试测试也无济于事。除此之外,我想我认为问题与缺少 MapHttpAttributeRoutes 有关。

标签: c# asp.net-web-api async-await nunit asp.net-web-api2


【解决方案1】:

检查Unit Testing Controllers in ASP.NET Web API 2中的测试链接生成

UrlHelper类需要请求URL和路由数据,所以测试 必须为这些设置值。

你没有在你的例子中设置这些,因此你的错误。

这是他们的一个例子

[TestMethod]
public void PostSetsLocationHeader()
{
    // Arrange
    ProductsController controller = new ProductsController(repository);

    controller.Request = new HttpRequestMessage { 
        RequestUri = new Uri("http://localhost/api/products") 
    };
    controller.Configuration = new HttpConfiguration();
    controller.Configuration.Routes.MapHttpRoute(
        name: "DefaultApi", 
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional });

    controller.RequestContext.RouteData = new HttpRouteData(
        route: new HttpRoute(),
        values: new HttpRouteValueDictionary { { "controller", "products" } });

    // Act
    Product product = new Product() { Id = 42, Name = "Product1" };
    var response = controller.Post(product);

    // Assert
    Assert.AreEqual("http://localhost/api/products/42", response.Headers.Location.AbsoluteUri);
}

根据那篇文章,您可以执行类似的操作,即使用 Moq 模拟 UrlHelper

[TestClass]
public class DemoControllerTests {
    [TestMethod]
    public async Task CreateFromDraftShouldSucceed() {
        // This version uses a mock UrlHelper.

        // Arrange
        var controller = new DemoController();
        controller.Request = new HttpRequestMessage();
        controller.Configuration = new HttpConfiguration();

        string locationUrl = "http://localhost/api/demo/1";

        // Create the mock and set up the Link method, which is used to create the Location header.
        // The mock version returns a fixed string.
        var mockUrlHelper = new Mock<UrlHelper>();
        mockUrlHelper.Setup(x => x.Link(It.IsAny<string>(), It.IsAny<object>())).Returns(locationUrl);
        controller.Url = mockUrlHelper.Object;

        // Act
        var request = "Hello World";
        var result = await controller.DemoRequestPost(request);
        var response = await result.ExecuteAsync(System.Threading.CancellationToken.None);

        // Assert
        Assert.AreEqual(locationUrl, response.Headers.Location.AbsoluteUri);
    }
}

【讨论】:

  • 不错,你知道第一个解决方案,但使用属性路由吗?
  • @dknaack,你能详细说明一下吗?我不明白你的意思?属性路由只对集成测试而不是单元测试重要。但是您仍然可以在安排测试时在HttpConfiguration 上调用映射扩展
  • 我想测试位置标头 url。为了做到这一点,我可能需要 Url Helper 才能工作。我可以调用运行良好的 HttpConfiguration MapHttpAttributeRoutes。但是 Url Helper 不会生成 url (null)。
  • 检查我提供的链接。他们有如何配置 UrlHelper 的示例。它需要一个有效的请求。
  • 我检查了链接。但这篇文章不涉及 AttributeRoutes。
【解决方案2】:

@dknaack 对于您的控制器测试,您可能不需要这行代码:

    var httpConfiguration = new HttpConfiguration();
    httpConfiguration.MapHttpAttributeRoutes();
    httpConfiguration.EnsureInitialized();
    controller.Configuration = httpConfiguration;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-21
    • 1970-01-01
    • 2017-03-22
    • 2016-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-11
    相关资源
    最近更新 更多