2011-12-15 135 views
9

我有一个用户类像这样:如何对使用springSecurityService的控制器进行单元测试?

class User { 
    transient springSecurityService 
    String displayName 
    String password 
<snip> 
    protected void encodePassword() { 
     password = springSecurityService.encodePassword(password) 
    } 
} 

并有UserController。 我试图写的UserController单元测试,但我得到这个错误保存,更新和删除测试:

java.lang.NullPointerException: Cannot invoke method encodePassword() on null object 

什么我必须建立在嘲讽得到这个方式工作?

我已经尝试过许多嘲笑代码的组合,比如下面的代码,但是我很茫然。

defineBeans { 
    springSecurityService(SpringSecurityService) 
} 

任何意见将不胜感激。

+0

我遇到了完全一样的问题。据我所知,根据文档,defineBeans()应该可以工作。不幸的是,它没有效果。 – 2012-04-26 03:00:05

回答

0

我已经做了这样的:

protected void encodePassword() { 
     // SpringSecutiryService is not injected in tests. 
     if (springSecurityService) 
      password = springSecurityService.encodePassword(formPassword) 
    } 
+2

这不是一个理想的解决方案,看起来更像是一个修复程序,让测试通过。如果安全服务在生产中出于某种奇怪的原因而被拒绝,那么该怎么办......然后,所有的密码都不会被散列(没有错误信息) – david 2012-01-11 16:02:22

+0

您是对的@david。 – 2012-01-12 10:23:57

8

我个人不喜欢添加逻辑到生产代码,以帮助满足检验。有时你必须决定什么是最好的。选项夫妇...

  1. 以上回答的工作,但正如我所说,我个人不喜欢
  2. 不要单元测试。将所有运行到这种情况的测试写入集成测试。
  3. 用假服务嘲笑它。

如果(在运行同样的问题或代码)这个代码是整个应用程序洒那么你可能想找出一种方法来模拟出在单元测试中,这些呼吁所有测试用例,所以你不要在任何地方复制你的设置。一个简单的方法来嘲笑这是与metaClassing。

@Test 
public void something() { 
    def user = ... 
    def springSecurityService = new Object() 
    springSecurityService.metaClass.encodePassword = {String password -> "ENCODED_PASSWORD"} 
    user.springSecurityService = springSecurityService 
    ... 
} 

现在,当springSecurityService.encodePassword被调用,它应该返回 “ENCODED_PASSWORD”。我也创建了一个Object,而不是实例化一个新的SpringSecurityService,因为如果你实例化一个实际的服务,那么你最终可能会意外地和不知不觉地调用该服务的实际方法,并让你的测试通过错误的原因。我宁愿得到一个没有这样的方法错误,而不是一个不应该传递的通过测试。

-1

在我的情况下,我试图覆盖SecUser的encodePassword()实现 - 它调用springSecurityService.encodePassword()。

我很惊讶,因为我需要覆盖类和实例(如果我没有覆盖任何,它失败):

SecUser.metaClass.encodePassword = { 'a' } 
user.metaClass.encodePassword = { 'b' } 

的,为什么我需要这个什么想法?

0

我认为正确的做法是嘲笑服务。您需要测试可能成为返回值的不同情况,并将正确的值传递给服务方法。

@Test 
public void something() { 
    def user = ... 
    def expectedPassword = 'mock encoded pass' 
    controller.springSecurityService = [encodePassword: { String passwd -> return expectedPassword }] 

    ... 
} 

@Test 
public void something() { 
    def user = ... 
    def expectedPassword = 'mock encoded pass' 
    def mockSecurityService = mockFor(SpringSecurityService) 
    mockSecurityService.demand.encodePassword { String passwd -> return expectedPassword} 
    controller.springSecurityService = mockSecurityService.createMock() 

    ... 
    mockSecurityService.verify() // throws exception if demands aren't met 
} 
相关问题