2011-10-24 19 views
2

在我简单的Index() ActionMethod我引用User.Identity属性。所以,我认为我需要嘲笑它。当我嘲笑我的ASP.NET MVC控制器时,我的ActionMethod返回没有视图。为什么?

所以我创建了一个模拟部分和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! 

任何想法,这是为什么?

+1

是否使用的是嘲讽库? –

+0

另外,你在这里测试什么?嘲笑图书馆是否工作? –

+0

我正在使用Moq,并且正在测试视图中返回的一些结果。我没有测试moq库本身。我认为这个问题是因为模拟控制器没有上下文和请求的东西,哪些ViewEngine需要? –

回答

2

我想你应该嘲笑一个的HttpContext为控制器的工作。 I provided one on another answer that you could use。正如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); 

下面你可以走得更远了一步,创建安装程序和TearDown方法以使用模拟的上下文来设置控制器。

1

说实话,这看起来像一个非常奇怪的测试,因为你嘲笑被测系统(SUT),换句话说HomeController。通常人们会嘲笑SUT的依赖关系,在模拟上设置预期,并将模拟注入SUT以确认它与其依赖关系正常交互。

当您创建HomeController的模拟时,Moq正在创建一个继承自HomeController并覆盖虚拟方法Index的类。所以,当你调用你不打电话的Index执行您在HomeController类中定义,但覆盖的一个模拟Index。既然你没有明确Setup模拟它的方法将返回默认值,在这种情况下,null

在你的第二个测试中,你调用Index的实际实现,因为你正在构造一个HomeController类的实际实例。如果您在模拟对象的实例调用GetType(),那么你会发现它是从HomeController其拦截调用基类的公共定义,重写的方法(这是目的有很大一部分派生的代理实例模拟对象)。

3

有在你的单元测试一些奇怪的事情。您正在对控制器进行单元测试,但是您正在模拟正在测试的对象的创建: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 
... 
+0

干杯!我会给这个前面的。作为一边......嗯..这让我想起了我在某处看到的一些代码......它在哪里。 –

+1

@ Pure.Krome,有[gazillions的地方](http://www.google.com/search?s?hl=en&sugexp=kjrmc&cp=35&gs_id=3l&xhr=t&q=moq%20asp.net%20mvc%20moq% 20user%20controller&PQ = MOQ + asp.net + MVC + MOQ +用户+控制器&PF = p&sclient = PSY-AB&安全=活性&站点=&源= HP&PBX = 1&OQ =&水溶液=&AQI =&AQL =&gs_sm =&gs_upl =&BAV = on.2,或。通过互联网,您可以找到这个代码,并通过互联网找到这些代码:r_gc.r_pw。,cf.osb&biw = 1680&bih = 945&ech = 2&psi = K0ilTsrKCYTqOYLE6fwE.1319454763487.4&emsg = NCSR&noj = 1&ei = M0ilTue3J9CXOsfX_L4N)。下面是一个例子:http://www.codethinked.com/simplified-aspnet-mvc-controller-testing-with-moq –

+0

昨晚我在工作后发现了它。它来自NerdDinner - 第12部分:http://nerddinnerbook.s3.amazonaws.com/Part12.htm :) :) –

1

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

但是,我同意其他答复,你不应该嘲笑你的控制器,但你应该嘲笑你的依赖。

(一个更简单的方法是创建一个可以从HttpContext的获取主要的专用模型绑定,那么你可以通过委托人作为输入参数,以你的方法)

相关问题