ASP.NET MVC: หน่วยควบคุมการทดสอบที่ใช้ UrlHelper


170

หนึ่งในตัวควบคุมของฉันการกระทำที่ถูกเรียกในคำขอ Ajax กำลังส่งคืน URL ไปยังฝั่งไคลเอ็นต์เพื่อให้สามารถทำการเปลี่ยนเส้นทางได้ ฉันกำลังใช้Url.RouteUrl(..)และระหว่างการทดสอบหน่วยของฉันสิ่งนี้ล้มเหลวเนื่องจากController.Urlพารามิเตอร์ไม่ได้ถูกเติมไว้ล่วงหน้า

ฉันพยายามมากของสิ่งอื่น ๆ ในกลุ่มพยายามที่จะต้นขั้วUrlHelper(ซึ่งล้มเหลว) ด้วยตนเองสร้างUrlHelperด้วยRequestContextที่มี stubbed HttpContextBase(ซึ่งล้มเหลวในRouteCollection.GetUrlWithApplicationPathการโทร)

ฉันค้นหาโดยใช้ Google แต่ไม่พบสิ่งใดเลยในเรื่องนี้ ฉันกำลังทำสิ่งที่โง่อย่างไม่น่าเชื่อที่ใช้Url.RouteUrlในการดำเนินการควบคุมของฉัน? มีวิธีที่ง่ายกว่านี้ไหม?

เพื่อให้แย่ยิ่งขึ้นฉันต้องการทดสอบ URL ที่ส่งคืนในการทดสอบหน่วยของฉัน - ในความเป็นจริงฉันสนใจเพียงแค่รู้ว่ามันกำลังเปลี่ยนเส้นทางไปยังเส้นทางที่ถูกต้อง แต่เนื่องจากฉันคืน URL แทน เส้นทางฉันต้องการควบคุม URL ที่ได้รับการแก้ไข (เช่นโดยการใช้ stubbed RouteCollection) - แต่ฉันยินดีที่จะผ่านการทดสอบของฉันเพื่อเริ่มต้น

คำตอบ:


202

นี่คือหนึ่งในการทดสอบของฉัน (xUnit + Moq) สำหรับกรณีที่คล้ายกัน (ใช้ Url.RouteUrl ในคอนโทรลเลอร์)

หวังว่านี่จะช่วย:

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
ในขณะที่ฉันไปกับการแก้ปัญหาที่ฉันโทรไป UrlHelper ดังนั้นฉันจึงสามารถสกัดกั้นพวกเขา ขอบคุณสำหรับตัวอย่างของคุณ แต่มันจะช่วยฉันได้มากในการหาวิธีการเลียนแบบ Request / Response / ControllerContext อย่างถูกต้อง
efdee

ขอบคุณสำหรับคำตอบ @ eu-ge-ne มันช่วยฉันออกมามากมายเช่นกัน ฉันได้รวมถึงบางส่วนการตั้งค่าขั้นต่ำในการใช้พารามิเตอร์ FormCollection ที่ใช้โดย UpdateModel
jebcrum

16
+1 ที่ยอดเยี่ยม แม้ว่าคำแนะนำ: ฉันใช้สิ่งนี้เป็น MockHelper และเปลี่ยนการตอบกลับการตั้งค่าสำหรับ ApplyAppPathModifier เป็น: response.Setup (x => x.ApplyAppPathModifier (Moq.It.IsAny <String> ()) ) => url); มันน่าเกลียด แต่ฉันได้รับวัตถุที่เป็นอนุกรมกลับมาในรูปแบบการเข้ารหัส URL แทนการเข้ารหัสค่าที่ส่งคืน
eduncan911

นั่นบางส่วนใช้งานได้สำหรับฉัน ความคิดใดที่ฉันได้รับ Controller / แทนที่จะเป็น Controller / Action? การทดสอบของฉันล้มเหลวเพราะมันไม่เหมือนกัน แต่ฉันลงทะเบียนค่าการเราต์เดียวกัน แปลกมาก ...
Nick

3
ApplyAppPathModifierส่วนหนึ่งเป็นบิตที่สำคัญสำหรับ UrlHelper
คริส S

37

การนำไปใช้ที่ปรับเปลี่ยนจาก eu-ge-ne อันนี้ส่งคืนลิงก์ที่สร้างขึ้นตามเส้นทางที่กำหนดไว้ในแอปพลิเคชัน ตัวอย่างของ eu-ge-ne ส่งคืนการตอบกลับที่แน่นอนเสมอ วิธีการด้านล่างจะช่วยให้คุณทดสอบว่าข้อมูลการดำเนินการ / ตัวควบคุมและเส้นทางที่ถูกต้องถูกส่งผ่านไปยัง UrlHelper - ซึ่งเป็นสิ่งที่คุณต้องการหากคุณกำลังทดสอบการโทรไปยัง 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

โพสต์นี้อาจมีประโยชน์หากคุณต้องการจำลองคลาส HttpContextBase

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


เยี่ยมสิ่งนี้ช่วยฉันแม้ว่าฉันต้องเพิ่มรหัสพิเศษบางอย่างในวิธี FakeHttpContext เพื่อหยุดผู้ช่วยที่ทำให้เกิดการระเบิด: context.Setup (ctx => ctx.Request.ApplicationPath). คืนค่า ("/ AntiBlowup"); ฉันปรับโครงสร้างโค้ดอีกครั้งเพื่อที่จะใช้ไวยากรณ์ Setup () ที่ใหม่กว่า ขอบคุณ
RichardOD

2

สร้างคำตอบโดย @ eu-ge-ne ซึ่งช่วยฉันได้มาก:

ฉันมี ActionResult ที่ทำการเปลี่ยนเส้นทางและมีการเรียก UpdateModel ด้วยพารามิเตอร์ FormCollection เพื่อให้ UpdateModel () ทำงานฉันต้องเพิ่มสิ่งนี้ลงใน Mocked HttpRequestBase ของฉัน:

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

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

ในการทดสอบว่า URL ที่เปลี่ยนเส้นทางถูกต้องคุณสามารถทำสิ่งต่อไปนี้:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.