【问题标题】:Grails. Testing command objects with spring beans inside圣杯。用里面的spring bean测试命令对象
【发布时间】:2017-03-19 14:38:18
【问题描述】:

我在自定义验证器中有一个带有约束的命令对象:

class UserPasswordCommand {
    String currentPassword
    //other fields....
    static constraints = {
        currentPassword validator: { currPass, upc ->
            Holders.applicationContext.passwordEncoder.isPasswordValid(
                    Holders.applicationContext.springSecurityService.currentUser.password, currPass, null)
        }
    }
}

但是在单元测试中调用 new UserPasswordCommand(...) 时,我得到以下信息:

java.lang.NullPointerException: 无法获取属性 'currentUser' on 空对象

看来 springSecurityService = null (如预期的那样)。我尝试了不同的操作来模拟或“元类”它,但没有成功。

请告知是否有更好的方法在命令对象中使用来自 applicationContext 的 bean 或在 Holders.applicationContext 中模拟 bean 的一些方法。

提前致谢!

更新

将以下内容放在setup() 部分:

def setup() {
    def appContext = Mock(ApplicationContext)
    def springSecurityService = Mock(SpringSecurityService)
    appContext.springSecurityService >> springSecurityService
    Holders.metaClass.static.applicationContext = { appContext }
}

但是没有效果。从 Holders 检索的 applicationContext 中的 springSecurityService 为 null。我做错了什么?

【问题讨论】:

  • 仅供参考,在命令对象中使用 Holders 是一个非常糟糕的主意。它会表现不佳。更好的方法是让 bean 构造函数参数并自己构造类。
  • @JamesKleeh,感谢您的信息。我将检索从持有人更改为普通 DI,并使字段静态。这个解决方案够好吗?

标签: spring unit-testing grails spock command-objects


【解决方案1】:

您可以像这样覆盖 Holder.applicationContext:

  def setup() {
    ApplicationContext appContext = Mock()
    PasswordEncoder passwordEncoder = Mock()
    passwordEncoder.isPasswordValid(_, _, _) >> true

    appContext.passwordEncoder >> passwordEncoder //you can do the same for springSecurityService

    //override Holder.getAplicationContext() method to return mocked context
    Holders.metaClass.static.applicationContext = { appContext }
}

【讨论】:

  • 您的意思是Holders 而不是Holder?可能是metaClass 而不是metaclass?
  • 是的,对不起,我无法访问笔记本,我刚刚更正了我的答案
  • 无效。我已经用新的setup() 部分更新了这个问题。
【解决方案2】:

我通过删除原始命令对象中的Holders 解决了这个问题:

class UserPasswordCommand {
    static passwordEncoder
    static springSecurityService
    String currentPassword
    //...
    static constraints = {
        currentPassword validator: { currPass, upc ->
    passwordEncoder.isPasswordValid(springSecurityService.currentUser.password, currPass, null)
        }
    //...
    }
}

添加了模拟/存根来测试测试:

def springSecurityService = Mock(SpringSecurityService)
def passwordEncoder = Mock(PasswordEncoder)

def setup() {
    passwordEncoder.isPasswordValid(_, _, _) >> Boolean.TRUE
    springSecurityService.currentUser >> Mock(User)
}

和:

given:
Map props = [
    currentPassword: CURRENT_PASSWORD,
    passwordEncoder: passwordEncoder,
    springSecurityService: springSecurityService,
]

expect:
new UserPasswordCommand(props).validate()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 2011-11-03
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多