8

Tôi đã làm việc theo cách của mình qua bài đăng tuyệt vời của Scott Guthrie trên ASP.NET MVC Beta 1. Trong đó, ông cho thấy những cải tiến được thực hiện cho phương pháp UpdateModel và cách họ cải thiện kiểm thử đơn vị. Tôi đã tạo lại một dự án tương tự tuy nhiên bất cứ lúc nào tôi chạy một UnitTest có chứa một cuộc gọi đến UpdateModel tôi nhận được một ArgumentNullException đặt tên tham số controllerContext.Làm thế nào để tôi kiểm tra đơn vị hành động mà không Mocking sử dụng UpdateModel?

Dưới đây là các bit có liên quan, bắt đầu với mô hình của tôi:

public class Country { 
    public Int32 ID { get; set; } 
    public String Name { get; set; } 
    public String Iso3166 { get; set; } 
} 

Hành động điều khiển:

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(Int32 id, FormCollection form) 
{ 
    using (ModelBindingDataContext db = new ModelBindingDataContext()) { 
    Country country = db.Countries.Where(c => c.CountryID == id).SingleOrDefault(); 

    try { 
     UpdateModel(country, form); 

     db.SubmitChanges(); 

     return RedirectToAction("Index"); 
    } 
    catch { 
     return View(country); 
    } 
    } 
} 

Và cuối cùng đơn vị của tôi kiểm tra đó là thất bại:

[TestMethod] 
public void Edit() 
{ 
    CountryController controller = new CountryController(); 
    FormCollection form = new FormCollection(); 
    form.Add("Name", "Canada"); 
    form.Add("Iso3166", "CA"); 

    var result = controller.Edit(2 /*Canada*/, form) as RedirectToRouteResult; 

    Assert.IsNotNull(result, "Expected to be redirected on successful POST."); 
    Assert.AreEqual("Show", result.RouteName, "Expected to redirect to the View action."); 
} 

ArgumentNullException được ném bằng cách gọi tới số UpdateModel với thông báo "Giá trị không được rỗng. P tên tham số: controllerContext ". Tôi giả định rằng một nơi nào đó số UpdateModel yêu cầu System.Web.Mvc.ControllerContext không có trong quá trình thực hiện kiểm tra.

Tôi cũng giả định rằng tôi đang làm điều gì đó sai ở đâu đó và chỉ cần chỉ đúng hướng.

Trợ giúp Xin vui lòng!

Trả lời

5

Tôi không nghĩ rằng nó có thể được thực hiện kể từ TryUpdateModel, mà UpdateModel sử dụng, tham chiếu đến ControllerContext là null khi được gọi từ một bài kiểm tra đơn vị. Tôi sử dụng RhinoMocks để mô phỏng hoặc khai thác các thành phần khác nhau mà bộ điều khiển cần.

var routeData = new RouteData(); 
var httpContext = MockRepository.GenerateStub<HttpContextBase>(); 
FormCollection formParameters = new FormCollection(); 

EventController controller = new EventController(); 
ControllerContext controllerContext = 
    MockRepository.GenerateStub<ControllerContext>(httpContext, 
                routeData, 
                controller); 
controller.ControllerContext = controllerContext; 

ViewResult result = controller.Create(formParameters) as ViewResult; 

Assert.AreEqual("Event", result.Values["controller"]); 
Assert.AreEqual("Show", result.Values["action"]); 
Assert.AreEqual(0, result.Values["id"]); 

Dưới đây là các bit có liên quan từ các nguồn Controller.cs trên www.codeplex.com/aspnet:

protected internal bool TryUpdateModel<TModel>(...) where TModel : class 
{ 

    .... 

    ModelBindingContext bindingContext = 
      new ModelBindingContext(ControllerContext, 
            valueProvider, 
            typeof(TModel), 
            prefix, 
            () => model, 
            ModelState, 
            propertyFilter); 

    ... 
} 
+1

Tôi đồng ý, tôi có thể giải quyết điều này bằng cách chế giễu, nhưng mà đi một cách rõ ràng chống lại những gì Scott nói trong bài của mình trong tham chiếu đến các ví dụ UpdateModel: "Chúng tôi không có để thử bất cứ điều gì để kiểm tra đơn vị cả hai kịch bản trình mẫu ở trên. " –

+0

tôi nhìn vào nguồn cho TryUpdateModel (mà UpdateModel sử dụng) và nó chắc chắn sử dụng ControllerContext. Tôi đã cập nhật phản hồi của mình với bit mã nguồn có liên quan. – tvanfosson

+0

@Hellfire, tôi thấy một bình luận trên bài viết trên blog rằng chỉ ra rằng ít nhất một người khác đã có những lỗi tương tự. Có thể là ModelBindingContext đã thay đổi trước khi Beta 1 ra khỏi cửa. – tvanfosson

0

Hoặc bạn có thể tạo ra hình thức dữ liệu proxy, như

public class CountryEdit { 
    public String Name { get; set; } 
    public String Iso3166 { get; set; } 
} 
  • Plus. Dễ dàng tạo các bài kiểm tra đơn vị
  • Plus. Xác định danh sách trắng các trường cập nhật từ bài đăng
  • Plus. Quy tắc xác thực thiết lập dễ dàng, dễ dàng kiểm tra nó.
  • Trừ. Bạn nên di chuyển ngày từ proxy để bạn mô hình

Vì vậy Controller.Action nên xem xét, như

public ActionResult Edit(Int32 id, CountryEdit input) 
{ 
    var Country = input.ToDb(); 
    // Continue your code 
} 
2

Tôi đã có vấn đề tương tự. Sau khi đọc giải pháp của tvanfosson, tôi đã thử một giải pháp đơn giản không liên quan đến một khuôn khổ giả.

Thêm một ControllerContext mặc định để bộ điều khiển như sau:

CountryController controller = new CountryController(); 
controller.ControllerContext = new ControllerContext(); 

này loại bỏ các lỗi chỉ tốt cho tôi trong khi kiểm tra đơn vị. Tôi hy vọng điều này có thể giúp đỡ người khác.

Các vấn đề liên quan