单元测试异步控制器:Url.Link上的异常()

时间:2016-07-19 18:21:56

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

我想对异步控制器进行单元测试。我以前做了很多次,但从未调用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);
    }
}

我正在接收

  

at NUnit.Framework.Internal.ExceptionHelper.Rethrow(异常异常)   at NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult)   at NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext context)

2 个答案:

答案 0 :(得分: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);
    }
}

答案 1 :(得分:0)

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

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