为什么不使用 Grails 3.2 为单元测试注入 sessionFactory?

Why is sessionFactory not injected for unit test using Grails 3.2?

我 运行 遇到一个问题,扩展 HibernateSpec 的单元测试因 sessionFactory 未注入被测服务而失败。每当在测试期间调用 sessionFactory 上的方法时,我都会得到 NullPointerException(例如 java.lang.NullPointerException: Cannot invoke method getClassMetadata() on null object),随后测试失败。

我正在使用 Grails 3.2.4 和 Hibernate 5。

这在测试使用 @TestMixin(HibernateTestMixin) 时有效,但看起来有些更新,mixin 已被弃用,建议改用 HibernateSpec

这是我的测试片段:

class TestDatabaseServiceSpec extends HibernateSpec {
    def setup() {
    }

    def cleanup() {
    }

    void "test method"() {
        when: 
        service.method() 

        then:
        true
    }
}

这里是被测服务的一个片段:

void method() {
...
  TABLE_NAMES.add(sessionFactory.getClassMetadata('MyDomain').tableName)
...
}

我曾尝试在 setup 方法中设置 service.sessionFactory 以及在测试中使用 sessionFactory 方法设置 setupSpec 方法,但不幸的是,这没有帮助。我考虑过使用集成测试,但我真的很想看看我是否可以继续让这个单元测试像以前一样工作。有谁知道我是不是做错了什么,或者是否有 workaround/solution?

谢谢!

查看 HibernateSpec 的源代码可以提供一些提示。可能是您正在使用的 Hibernate 5 grails 插件中没有 getSessionFactory() 方法。

我将 org.grails.plugins:hibernate5:6.0.6 与 grails 3.2.5 一起使用,并且在单元测试中 sessionFactory 对我来说不为空。

我知道并非总是可以升级,但它可以让您了解问题的根源。

更新:

service.sessionFactory = sessionFactory

也必须在测试设置中调用。

对我有用的是在规范中添加注解 @FreshRuntime 并在为我设置 sessionFactory 的测试中添加 doWithSpring 闭包(即 sessionFactory( InstanceFactoryBean、sessionFactory、SessionFactory))。另外,我确保将 service.sessionFactory = sessionFactoryservice.transactionManager = transactionManager 添加到 setupSpec 方法中。最后,我需要覆盖 getDomainClasses() 以使用我想要在测试中使用的所有域对象。感谢大家的帮助!

自 3.2.3 以来,新特性的测试混合已被弃用。 https://docs.grails.org/latest/guide/testing.html

Since Grails 3.3, the Grails Testing Support Framework is used for all unit tests. This support provides a set of traits.

但是,我仍然发现自己在使用 HibernateSpec,因为我可以从中获得多个域 classes,以及服务的 ServiceUnitTest。 HibernateSpec 具有所需的 sessionFactory。 例如

class MyServiceSpec extends HibernateSpec implements ServiceUnitTest<MyService>{

    List<Class> getDomainClasses() { [Tag, TagLink, TagLinkValue, TagValue, TestDomain] }
...
    def setup() {
        service.sessionFactory = sessionFactory
...
    }
// tests here with all those domain classes available and the service 
}

DataTest 允许多个域 classes,但服务也不允许。 https://testing.grails.org/latest/guide/index.html#unitTestingDomainClasses

服务测试允许服务,但不允许多个域 classes。 https://testing.grails.org/latest/guide/index.html#unitTestingServices

您可以同时使用它们,但它们都没有会话工厂(我可以看到),我使用的是 Grails 4.0.1。我查看了最新的 Github 代码,但仍然看不到它可用。另外,DataTest 不是休眠会话,而是使用 SimpleMap,因此您不能将 hql 与它一起使用,这是我想要的。

我的服务使用的是 statelessSession

def statelessSession = sessionFactory.openStatelessSession()
String queryString = "select DISTINCT(t.tagRef) from com.fmr.aps.taggable.TagLink t group by t.tagRef order by t.tagRef ASC"
Query query = statelessSession.createQuery(queryString)
query.setReadOnly(true);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);

所以我需要一个单元测试特征或基础class,我花了几个小时试图让新特征给我想要的东西。甚至我开始对 DataTest class 进行子class 尝试让它给我 sessionFactory,但最终还是使用 HibernateSpec 并且很高兴能够 运行该测试 class 具有多个域、服务和 sessionFactory。