Как насмехаться с Controller.User с помощью moq
У меня есть несколько ActionMethods, которые запрашивают Controller.User за его роль, подобную этой
bool isAdmin = User.IsInRole("admin");
действуя удобно в этом условии.
Я начинаю делать тесты для этих методов с кодом вроде этого
[TestMethod]
public void HomeController_Index_Should_Return_Non_Null_ViewPage()
{
HomeController controller = new HomePostController();
ActionResult index = controller.Index();
Assert.IsNotNull(index);
}
и что тест завершается с ошибкой, так как Controller.User не установлен.
Любая идея?
Ответы
Ответ 1
Вам нужно выполнить Mock ControllerContext, HttpContextBase и, наконец, IPrincipal, чтобы высмеять свойство пользователя на контроллере. Используя Moq (v2), должно работать что-то по следующим строкам.
[TestMethod]
public void HomeControllerReturnsIndexViewWhenUserIsAdmin() {
var homeController = new HomeController();
var userMock = new Mock<IPrincipal>();
userMock.Expect(p => p.IsInRole("admin")).Returns(true);
var contextMock = new Mock<HttpContextBase>();
contextMock.ExpectGet(ctx => ctx.User)
.Returns(userMock.Object);
var controllerContextMock = new Mock<ControllerContext>();
controllerContextMock.ExpectGet(con => con.HttpContext)
.Returns(contextMock.Object);
homeController.ControllerContext = controllerContextMock.Object;
var result = homeController.Index();
userMock.Verify(p => p.IsInRole("admin"));
Assert.AreEqual(((ViewResult)result).ViewName, "Index");
}
Тестирование поведения, когда пользователь не является администратором, так же просто, как изменение ожидания, установленного для объекта userMock, для возврата false.
Ответ 2
Использование версии Moq 3.1 (и NUnit):
[Test]
public void HomeController_Index_Should_Return_Non_Null_ViewPage()
{
// Assign:
var homeController = new HomeController();
Mock<ControllerContext> controllerContextMock = new Mock<ControllerContext>();
controllerContextMock.Setup(
x => x.HttpContext.User.IsInRole(It.Is<string>(s => s.Equals("admin")))
).Returns(true);
homeController.ControllerContext = controllerContextMock.Object;
// Act:
ActionResult index = homeController.Index();
// Assert:
Assert.IsNotNull(index);
// Place other asserts here...
controllerContextMock.Verify(
x => x.HttpContext.User.IsInRole(It.Is<string>(s => s.Equals("admin"))),
Times.Exactly(1),
"Must check if user is in role 'admin'");
}
Обратите внимание, что нет необходимости создавать mock для HttpContext, Moq поддерживает вложенность свойств при настройке теста.
Ответ 3
При использовании AspNetCore я не мог издеваться над ControllerContext
, так как получил исключение.
Unsupported expression: m => m.HttpContext
Non-overridable members (here: ActionContext.get_HttpContext) may not be used in setup/verification expressions.
Вместо этого мне пришлось издеваться над HttpContext
, создать ControllerContext
и передать объект HttpContext
.
Я обнаружил, что поддельные утверждения или объекты ответа/запроса также хорошо работают при использовании этого метода.
[Test]
public void TestSomeStuff() {
var name = "some name";
var httpContext = new Mock<HttpContext>();
httpContext.Setup(m => m.User.IsInRole("RoleName")).Returns(true);
httpContext.Setup(m => m.User.FindFirst(ClaimTypes.Name)).Returns(name);
var context = new ControllerContext(new ActionContext(httpContext.Object, new RouteData(), new ControllerActionDescriptor());
var controller = new MyController()
{
ControllerContext = context
};
var result = controller.Index();
Assert.That(result, Is.Not.Null);
}