Когда я издеваюсь над своим контроллером ASP.NET MVC, мой ActionMethod не возвращает представления. Почему?

В моем простом Index() ActionMethod я ссылаюсь на свойство User.Identity. Итак, я подумал, что мне нужно издеваться над этим.

Поэтому я создаю макет HomeController и использую его в своем модульном тесте. Когда я это делаю, ActionMethod возвращает null в качестве представления. Когда я заменяю mock-контроллер конкретным экземпляром (и, конечно же, закомментирую любую ссылку на User.Identity), тогда возвращается правильное представление.

eg.

// Arrange.
var homeController = Mock<HomeController>(..);
homeController.Setup(x => x.User).Returns(new GenericPrincipal(..));

// Act.
var result = homeController.Index();

// Assert.
Assert.IsNotNull(result); // This fails here. result is NULL.

но когда я делаю это (и комментирую любую ссылку User), это работает...

// Arrange.
var homeController = new HomeController(..);

// Act.
var result = homeController.Index();

// Assert.
Assert.IsNotNull(result); // Tick!

Есть идеи, почему это так?


person Pure.Krome    schedule 24.10.2011    source источник
comment
Какую издевательскую библиотеку вы используете?   -  person Lasse V. Karlsen    schedule 24.10.2011
comment
Кроме того, что конкретно вы тестируете здесь? Работает ли мокационная библиотека?   -  person Lasse V. Karlsen    schedule 24.10.2011
comment
Я использую Moq и тестирую некоторые результаты, которые возвращаются в представлении. Я не тестирую саму библиотеку moq. Я думаю, проблема в том, что фиктивный контроллер не имеет контекста и запросов, которые нужны ViewEngine?   -  person Pure.Krome    schedule 24.10.2011
comment
Также добавлен минимальный объем заказа в качестве тега.   -  person Pure.Krome    schedule 24.10.2011
comment
Я имел в виду, что вы издеваетесь над контроллером, что означает, что контроллер, на котором вы вызываете .Index(), является макетом, что не имеет смысла. Этот макет никогда ничего не сделает, если только вы явно не скажете ему делать что-то или возвращать что-то. Другими словами, вы тестируете макет.   -  person Lasse V. Karlsen    schedule 24.10.2011
comment
@LasseV.Karlsen - да! полностью согласен! Я постоянно путаюсь, тестируя что-то, над чем издевался, что НАСТОЛЬКО неправильно blush. Моки нужны, чтобы помочь моим тестам.   -  person Pure.Krome    schedule 26.10.2011


Ответы (4)


Я думаю, вы должны издеваться над HttpContext для работы контроллера. Я предоставил один ответ на другой, который вы могли бы использовать. Как Стив Роуботам говорит, что вы должны имитировать зависимости тестируемой системы (т.е. зависимости контроллера), а не саму тестируемую систему; вы хотите протестировать настоящую версию контроллера, а не макет :)

Используя класс HttpContextBase из ссылки, вы просто сделаете следующее в своем тесте

var controllerToTest = new HomeController();
var context = new MockHttpContextBase(controllerToTest);

// do stuff that you want to test e.g. something goes into session

Assert.IsTrue(context.HttpContext.Session.Count > 0); 

Вы можете пойти еще дальше и создать методы Setup и TearDown, чтобы настроить контроллер с фиктивным контекстом.

person Russ Cam    schedule 24.10.2011

В вашем модульном тесте есть некоторые странные вещи. Вы выполняете модульное тестирование контроллера и все же издеваетесь над созданием тестируемого объекта: var homeController = Mock<HomeController>(..); что неверно.

Вот правильный способ внедрить фиктивного пользователя в контроллер, который вы хотите протестировать:

// arrange
var sut = new HomeController();
var user = new GenericPrincipal(new GenericIdentity("foo"), null);
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(x => x.User).Returns(user);
var context = new ControllerContext(new RequestContext(httpContext.Object, new RouteData()), sut);
sut.ControllerContext = context;

// act
var actual = sut.Index();

// assert
...
person Darin Dimitrov    schedule 24.10.2011
comment
Ваше здоровье! Я отдам это назад. Кстати... Хм... это напоминает мне какой-то код, который я где-то видел.... где он был. - person Pure.Krome; 24.10.2011
comment
@Pure.Krome, есть миллионы мест в Интернете, где вы найдете миллионы мест. Вот пример: codethinked.com/ - person Darin Dimitrov; 24.10.2011
comment
Я нашел его прошлой ночью после того, как ушел с работы. Это было из NerdDinner - часть 12: nerddinnerbook.s3.amazonaws.com/Part12.htm :) :) - person Pure.Krome; 25.10.2011

Честно говоря, это выглядит очень странным тестом, потому что вы имитируете тестируемую систему (SUT), другими словами, HomeController. Обычно можно имитировать зависимости ТРИ, устанавливать ожидания для макета и внедрять макет в ТРИ, чтобы подтвердить, что он правильно взаимодействует со своими зависимостями.

Когда вы создаете макет HomeController, Moq создает класс, который наследуется от HomeController и переопределяет виртуальный метод Index. Поэтому, когда вы вызываете Index в макете, вы вызываете не реализацию Index, которую вы определили в классе HomeController, а переопределенную. Поскольку вы явно не указали метод Setup в макете, он вернет значение по умолчанию, в данном случае null.

Во втором тесте вы вызываете фактическую реализацию Index, потому что вы создаете фактический экземпляр класса HomeController. Если вы вызовете GetType() для экземпляра фиктивного объекта, то увидите, что это экземпляр прокси-сервера, производного от HomeController, который перехватывает вызовы к публично определенным, переопределяемым методам базового класса (что является большой частью цели). мнимого объекта).

person Steve Rowbotham    schedule 24.10.2011

Я думаю, что ваш метод Index, вероятно, является виртуальным, из-за чего Moq заменяет эту функцию имитируемой функцией. Чтобы предотвратить это, вам нужно установить свойство CallBase на макете.

Тем не менее, я согласен с другими ответами, что вы не должны издеваться над своим контроллером, но вы должны издеваться над своей зависимостью.

(еще более простой метод заключается в создании специализированного связывателя модели, который может извлекать принципала из HttpContext, после чего вы можете просто передать принципала в качестве входного параметра в свой метод)

person Pete    schedule 24.10.2011