繁体   English   中英

当我模拟ASP.NET MVC控制器时,我的ActionMethod不返回任何视图。 为什么?

[英]When I mock my ASP.NET MVC controller, my ActionMethod returns no view. Why?

在我简单的Index() ActionMethod中,我引用了User.Identity属性。 因此,我认为我需要对此进行嘲笑。

所以我创建了一个模拟的HomeController并在我的单元测试中使用了它。 当我这样做时, ActionMethod返回null作为视图。 当我用具体实例替换模拟控制器时(当然,请注释掉对User.Identity所有引用),然后返回正确的视图。

例如。

// 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!

任何想法为什么会这样?

您的单元测试中有一些奇怪的事情。 您正在对控制器进行单元测试,但是正在var homeController = Mock<HomeController>(..);被测对象的创建: 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
...

我认为您应该模拟HttpContext以便控制器使用。 我提供了另一个可以使用的答案 正如史蒂夫·罗伯瑟姆Steve Rowbotham)所说,您应该模拟被测系统的依赖性(即控制器的依赖性),而不是模拟被测系统本身。 您想测试控制器的真实版本而不是模拟的:)

使用链接中的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方法以使用模拟的上下文设置控制器。

老实说,这看起来像是一个非常奇怪的测试,因为您正在模拟被测系统(SUT),换句话说就是HomeController 通常,将模拟SUT的依赖关系,设置对模拟的期望,然后将模拟注入SUT以确认其与依赖关系正确交互。

当您创建HomeController的模拟时,Moq将创建一个从HomeController继承并覆盖虚拟方法Index 因此,当您在模拟对象上调用Index时,您不是在调用HomeController类中定义的Index的实现,而是调用已重写的实现。 由于尚未在模拟中显式Setup方法,因此它将返回默认值,在这种情况下为null

在第二个测试中,您正在调用Index的实际实现,因为您正在构造HomeController类的实际实例。 如果在模拟对象的实例上调用GetType() ,则会看到它是从HomeController派生的代理实例,该代理拦截对基类上公共定义的,可重写方法的调用(这是模拟对象的目的)。

我认为您的Index方法可能是虚拟的,这会导致Moq用模拟函数替换该函数。 为了防止这种情况,您需要在模拟上设置Call​​Base属性。

但是,我同意其他答复,即您不应模拟控制器,而应模拟依赖性。

(一个更简单的方法是创建一个可以从HttpContext提取主体的专用模型绑定程序,然后可以将主体作为输入参数传递给您的方法)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM