Как мне выполнить юнит тестовые действия без Mocking, которые используют UpdateModel? - PullRequest
8 голосов
/ 01 декабря 2008

Я пробираюсь через отличный пост Скотта Гатри на ASP.NET MVC Beta 1 . В нем он показывает улучшения, внесенные в метод UpdateModel, и как они улучшают юнит-тестирование. Я воссоздал аналогичный проект, однако каждый раз, когда я запускаю UnitTest, который содержит вызов UpdateModel, я получаю ArgumentNullException с именем controllerContext.

Вот соответствующие биты, начиная с моей модели:

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

Действие контроллера:

[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);
    }
  }
}

И, наконец, мой модульный тест не пройден:

[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 вызывается вызовом UpdateModel с сообщением «Значение не может быть нулевым. Имя параметра: controllerContext». Я предполагаю, что где-то UpdateModel требует System.Web.Mvc.ControllerContext, которого нет во время выполнения теста.

Я также предполагаю, что где-то делаю что-то не так, и мне просто нужно указать в правильном направлении.

Помогите пожалуйста!

Ответы [ 3 ]

5 голосов
/ 01 декабря 2008

Я не думаю, что это может быть сделано, поскольку TryUpdateModel, который использует UpdateModel, ссылается на ControllerContext, который является нулевым при вызове из модульного теста. Я использую RhinoMocks, чтобы смоделировать или заглушить различные компоненты, необходимые для контроллера.

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"] );

Вот соответствующий бит из источника Controller.cs на www.codeplex.com/aspnet:

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

     ....

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

     ...
}
2 голосов
/ 03 декабря 2010

У меня была такая же проблема. Прочитав решение tvanfosson, я попробовал простое решение, не включающее фиктивный фреймворк.

Добавьте ControllerContext по умолчанию к контроллеру следующим образом:

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

Это исправило ошибку для меня при юнит-тестировании. Я надеюсь, что это может помочь кому-то еще.

0 голосов
/ 31 марта 2010

Или вы можете создать прокси данных формы, как

public class CountryEdit {
  public String Name { get; set; }
  public String Iso3166 { get; set; }
}
  • Plus. Легко создавать юнит-тесты
  • Plus. Определить белый список полей обновления из поста
  • Plus. Простая настройка правил проверки, простая проверка.
  • минус. Вам нужно перенести дату с прокси на вашу модель

Итак, Controller.Action должен выглядеть, как

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