ASP.NET MVC: Bộ điều khiển kiểm tra đơn vị sử dụng UrlHelper


170

Một trong những hành động của bộ điều khiển của tôi, một hành động đang được gọi trong yêu cầu Ajax, đang trả lại một URL cho phía máy khách để nó có thể thực hiện chuyển hướng. Tôi đang sử dụng Url.RouteUrl(..)và trong quá trình kiểm tra đơn vị của mình, điều này không thành công do Controller.Urltham số không được điền sẵn.

Tôi đã thử rất nhiều thứ, trong số những thứ khác đang cố gắng sơ khai UrlHelper(thất bại), tự tạo một cái UrlHelpercó một RequestContextcái còn sơ khai ( HttpContextBasethất bại trong một RouteCollection.GetUrlWithApplicationPathcuộc gọi).

Tôi đã tìm kiếm Google nhưng hầu như không tìm thấy gì về chủ đề này. Tôi có đang làm điều gì đó cực kỳ ngu ngốc khi sử dụng Url.RouteUrltrong hành động Điều khiển của mình không? Có cách nào dễ hơn không?

Để làm cho nó tệ hơn nữa, tôi muốn có thể kiểm tra URL được trả về trong bài kiểm tra đơn vị của mình - thực tế tôi chỉ quan tâm đến việc biết nó đang chuyển hướng đến đúng tuyến đường, nhưng vì tôi trả lại một URL thay vì một tuyến đường, tôi muốn kiểm soát URL đã được giải quyết (ví dụ: bằng cách sử dụng gốc RouteCollection) - nhưng tôi sẽ rất vui khi bắt đầu bài kiểm tra của mình.

Câu trả lời:


202

Đây là một trong những thử nghiệm của tôi (xUnit + Moq) chỉ dành cho trường hợp tương tự (sử dụng Url.RouteUrl trong bộ điều khiển)

Hi vọng điêu nay co ich:

var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);

var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());

var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost/post1");

var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);

var controller = new LinkbackController(dbF.Object);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);

2
Hiện tại tôi đã đi với một giải pháp trong đó tôi trừu tượng hóa các cuộc gọi đến UrlHelper để tôi có thể chặn chúng. Tuy nhiên, cảm ơn về đoạn trích của bạn, nó sẽ giúp tôi tiết kiệm rất nhiều thời gian để tìm ra cách chế giễu chính xác Yêu cầu / Phản hồi / Trình điều khiển.
efdee

Cảm ơn câu trả lời @ eu-ge-ne, nó cũng giúp tôi rất nhiều. Tôi đã bao gồm một số thiết lập moq khác để sử dụng tham số formcollection được UpdateModel
jebcrum

16
+1 xuất sắc. Mặc dù một mẹo: Tôi sử dụng điều này như một MockHelper và thay đổi phản hồi.Setup cho ApplyAppPathModifier thành này: answer.Setup (x => x.ApplyAppPathModifier (Moq.It.IsAny <String> ())) ) => url); Thật là xấu, nhưng tôi lấy lại đối tượng được tuần tự hóa ở dạng mã hóa url, thay vì mã hóa giá trị được trả về.
eduncan911

Điều đó một phần làm việc cho tôi. Bất cứ ý tưởng tại sao tôi nhận được Bộ điều khiển / thay vì Bộ điều khiển / Hành động? Thử nghiệm của tôi thất bại vì chúng không hoàn toàn giống nhau và tôi vẫn đăng ký các giá trị định tuyến giống nhau. Rất kỳ quặc ...
Nick

3
Phần ApplyAppPathModifiernày là bit quan trọng cho UrlHelper
Chris S

37

Một triển khai sửa đổi từ eu-ge-ne. Liên kết này trả về một liên kết được tạo dựa trên các tuyến được xác định trong ứng dụng. Ví dụ của eu-ge-ne luôn trả về một phản hồi cố định. Cách tiếp cận dưới đây sẽ cho phép bạn kiểm tra xem thông tin hành động / bộ điều khiển và lộ trình chính xác đang được truyền vào UrlHelper - đây là điều bạn muốn nếu bạn đang kiểm tra lệnh gọi tới UrlHelper.

var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();

context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);

request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new NameValueCollection());

response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(x => x);

context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);

var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
var helper = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);

12

Bài đăng này có thể hữu ích nếu bạn muốn mô phỏng lớp HttpContextBase.

http://www.hanselman.com/blog/ASPNETMVCSessionAtMix08TDDAndMvcMockHelpers.aspx


Thật tuyệt, điều này đã giúp tôi, mặc dù tôi đã phải thêm một số mã bổ sung vào phương thức FakeHttpContext để ngăn người trợ giúp nổ tung: bối cảnh.Setup (ctx => ctx.Request.ApplicationPath) .Returns ("/ AntiBlowup"); Tôi cũng đã cấu trúc lại mã để nó sử dụng cú pháp Setup () mới hơn. Cảm ơn.
RichardOD

2

Xây dựng câu trả lời của @ eu-ge-ne đã giúp tôi rất nhiều:

Tôi đã có một ActionResult đã thực hiện chuyển hướng cũng như có một lệnh gọi UpdateModel với tham số FormCollection. Để UpdateModel () hoạt động, tôi đã phải thêm cái này vào Mocked HttpRequestBase:

FormCollection collection = new FormCollection();
collection["KeyName"] = "KeyValue";

request.Setup(x => x.Form).Returns(collection);
request.Setup(x => x.QueryString).Returns(new NameValueCollection());

Để kiểm tra rằng URL được chuyển hướng là chính xác, bạn có thể làm như sau:

RedirectResult result = controller.ActionName(modelToSubmit, collection) as RedirectResult;
Assert.AreEqual("/Expected/URL", result.Url);

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.