简单 grails 控制器单元测试中的空指针
Posted
技术标签:
【中文标题】简单 grails 控制器单元测试中的空指针【英文标题】:Nullpointer in simple grails controller unit test 【发布时间】:2014-08-28 14:57:32 【问题描述】:我需要一些帮助来解决我在对一个非常基本的 Grails 2.4.1 控制器进行单元测试时遇到的一个奇怪问题。
给定这个控制器:
class AuthenticationEventController
def index()
// Sorry, ajax only!
if(!request.xhr)
redirect(controller: "main")
return false
render(template: "index")
return
还有这个测试:
@TestFor(AuthenticationEventController)
class AuthenticationEventControllerSpec extends Specification
void "Test that the index rejects non-ajax calls"()
given:
request.isXhr = false
when:
controller.index()
then:
response.redirectedUrl == '/main'
我在“controller.index()”调用中收到 NullPointerException。
java.lang.NullPointerException
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
at org.codehaus.groovy.grails.orm.support.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:85)
at au.com.intrinsicminds.advansys.controller.AuthenticationEventControllerSpec.Test that the index rejects non-ajax calls(AuthenticationEventControllerSpec.groovy:17)
【问题讨论】:
您的测试在 grails 2.3.8 中通过(我还没有 2.4.1),所以也许它是 grails 缓存的东西 - 如果您还没有尝试过 grails clean 的话?否则,可能值得看看 Grails 2.4 中的变化 为了让它在 2.4.1 中工作,我必须在测试中添加一个空的 def setup() 和 def cleanup() 方法,否则我得到方法未找到错误,也许你值得一试吗? 2.4.0 和 2.4.1 都有一些严重的问题,这些问题在 2.4.2 中得到了解决。我没有机会尝试您的测试,但如果可能,我会考虑迁移到 2.4.2。 你不应该需要一个空的setup()
或cleanup()
方法,你不应该升级到2.4.2 来测试它。 github.com/jeffbrown/xhrtest 的项目包含我粘贴到下面答案中的代码,并且该测试似乎有效。
【参考方案1】:
问题很可能是您正在使用
import grails.transaction.Transactional
而不是
import org.springframework.transaction.annotation.Transactional
用于 groovy 类中的 @Transactional
注释。
为什么,对于主要区别或为什么测试对此效果不佳没有明确的答案。 此外,这通常仅在您测试一个具有 2 个以上类层的类时才会发生。
【讨论】:
就我而言,我在来自 grails/src 的 spring bean 中使用 grails.transaction.Transactional。我将它切换为使用 spring 的 @Transactional,它似乎已经解决了这个问题。 我在测试中也遇到了这个问题,但我的问题是我使用 grails.transaction.Transactional 时没有从 spring 上下文中获取对象。我只是为测试创建对象,因为我不需要我正在测试的部分的依赖项。使用 spring 注释将在测试时起作用,但在运行时不起作用,而 grails 注释会发生相反的情况。我不得不返回测试并允许 spring 上下文注入我正在测试的对象。 这个修复也适用于我。在我使用invokeMethod 在元编程中找到NPE 之后。如果没有 NPE,grails.transaction.Transactional 一切正常【参考方案2】:您是否在代码中的其他任何地方使用域类?我遇到了同样的问题(TransactionTemplate#execute 引发的 NPE),解决方案是根据这个 jira 问题将@Mock 用于我的一个实体:https://jira.grails.org/browse/GRAILS-11045
【讨论】:
【参考方案3】:以下内容适用于 Grails 2.4.1。
控制器:
// grails-app/controllers/demo/AuthenticationEventController.groovy
package demo
class AuthenticationEventController
def index()
if(!request.xhr)
redirect(controller: "main")
else
render(template: "index")
单元测试:
// test/unit/demo/AuthenticationEventControllerSpec.groovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
@TestFor(AuthenticationEventController)
class AuthenticationEventControllerSpec extends Specification
void "Test that the index redirects for non-ajax calls"()
when:
controller.index()
then:
response.redirectedUrl == '/main'
void "Test that index renders template for ajax calls"()
given:
request.makeAjaxRequest()
views['/authenticationEvent/_index.gsp'] = 'my template text'
when:
controller.index()
then:
response.contentAsString == 'my template text'
希望对你有帮助。
【讨论】:
【参考方案4】:我在尝试 Spy Transactional 服务时得到了相同的堆栈跟踪。
我找到了对我有帮助的解决方案。所以我只是在间谍服务中初始化 transactionManager。
参见示例:
SomeTransactionalService sts = Spy(SomeTransactionalService)
sts.transactionManager = transactionManager // so you need to add init transactionManager
【讨论】:
以上是关于简单 grails 控制器单元测试中的空指针的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Grails 单元测试中使用 Spock 模拟 passwordEncoder
SpringBug记录 -- java.lang.NullPointerException在Spring单元测试中遇到的空指针异常及依赖注入异常总结