测试WebApi控制器Url.Link
我有以下控制器操作
public void Post(Dto model) { using (var message = new MailMessage()) { var link = Url.Link("ConfirmAccount", new { model.Id }); message.To.Add(model.ToAddress); message.IsBodyHtml = true; message.Body = string.Format(@"Click here to complete your registration.
You may also copy and paste this link into your browser.
{0}
", link); MailClient.Send(message); } }
为了测试这个,我需要设置控制器上下文
var httpConfiguration = new HttpConfiguration(new HttpRouteCollection { { "ConfirmAccount", new HttpRoute() } }); var httpRouteData = new HttpRouteData(httpConfiguration.Routes.First()); var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost"); sut = new TheController { ControllerContext = new HttpControllerContext(httpConfiguration, httpRouteData, httpRequestMessage), MailClient = new SmtpClient { PickupDirectoryLocation = location } };
这似乎是很多设置来测试链接的创建。 有更清洁的方法吗? 我已经阅读过有关内存服务器的内容,但看起来它比httpclient更适用于直接测试控制器。
我开始在Web API 2.0中使用这种方法。
如果你正在使用一个模拟库(你真的应该用于任何真实世界的unit testing),你可以直接模拟UrlHelper
对象,因为它上面的所有方法都是virtual
。
var mock = new Mock(); mock.Setup(m => m.Link(It.IsAny(), It.IsAny
这是比Ben Foster的答案更清晰的解决方案,因为使用这种方法,您需要为您正在使用的每个名称添加路由到配置。 这可能很容易改变或成为一个可笑的大量路线设置。
以下是在没有任何类型的模拟库的情况下测试UrlHelper
所需的绝对最小代码。 扔我的东西(并花了我一些时间追踪)是你需要设置请求的IHttpRouteData
。 如果不这样做, IHttpRoute
实例将无法生成导致空URL的虚拟路径。
public class FooController : ApiController { public string Get() { return Url.Link(RouteNames.DefaultRoute, new { controller = "foo", id = "10" }); } } [TestFixture] public class FooControllerTests { FooController controller; [SetUp] public void SetUp() { var config = new HttpConfiguration(); config.Routes.MapHttpRoute( name: "Default", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }); var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost"); request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config; request.Properties[HttpPropertyKeys.HttpRouteDataKey] = new HttpRouteData(new HttpRoute()); controller = new FooController { Request = request }; } [Test] public void Get_returns_link() { Assert.That(controller.Get(), Is.EqualTo("http://localhost/api/foo/10")); } }
我遇到了同样的白痴。 我能找到的所有引用都希望你模拟请求/控制器,这是(正如你所指出的)很多工作。
具体参考:
- http://aspnetwebstack.codeplex.com/discussions/358709/
- http://www.peterprovost.org/blog/2012/06/16/unit-testing-asp-dot-net-web-api/#testing-the-harder-stuff-postproduct
- ASP.NET MVC控制器unit testing – UrlHelper扩展问题
- ASP.NET MVC:使用UrlHelper的unit testing控制器
- 互联网的其余部分
我还没有尝试过实际的Mocking框架,所以我有一个帮助类来“构建”我的控制器。 而不是
sut = new TheController { ... }
我使用类似的东西:
// actually rolled together to `sut = MyTestSetup.GetController(method, url)` sut = new TheController()... MyTestSetup.FakeRequest(sut, HttpMethod.Whatever, "~/the/expected/url");
作为参考,该方法基本上是:
public void FakeRequest(ApiController controller, HttpMethod method = null, string requestUrl = null, string controllerName = null) { HttpConfiguration config = new HttpConfiguration(); // rebuild the expected request var request = new HttpRequestMessage( null == method ? this.requestMethod : method, string.IsNullOrWhiteSpace(requestUrl) ? this.requestUrl : requestUrl); //var route = System.Web.Routing.RouteTable.Routes["DefaultApi"]; var route = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}"); // TODO: get from application? maybe like https://stackoverflow.com/a/5943810/1037948 var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", string.IsNullOrWhiteSpace(controllerName) ? this.requestController : controllerName } }); controller.ControllerContext = new HttpControllerContext(config, routeData, request); // attach fake request controller.Request = request; controller.Request.Properties[/* "MS_HttpConfiguration" */ HttpPropertyKeys.HttpConfigurationKey] = config; }