2016-04-27 88 views
2

我正在尝试为Spring 4 MVC项目编写集成测试。在我使用Spring Data JPA Repositories和Hibernate的项目中。尝试使用Spring Data JPA存储库执行集成测试返回NullPointerException

下面是两个文件,即集成测试本身和用于设置我的持久性配置的配置。

PersistenceTestConfiguration.java

package <project>.cms.rest.test.configuration; 

import <project>.cms.rest.entity.EntityMarker; 
import <project>.cms.rest.repository.RepositoryMarker; 
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; 
import org.jasypt.hibernate3.encryptor.HibernatePBEEncryptorRegistry; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; 
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 
import org.springframework.orm.hibernate4.HibernateExceptionTranslator; 
import org.springframework.orm.jpa.JpaTransactionManager; 
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 
import org.springframework.transaction.PlatformTransactionManager; 
import org.springframework.transaction.annotation.EnableTransactionManagement; 

import javax.naming.NamingException; 
import javax.persistence.EntityManagerFactory; 

@Configuration 
@EnableTransactionManagement 
@EnableJpaRepositories(basePackageClasses = {RepositoryMarker.class}) 
public class PersistenceTestConfiguration { 

    @Bean 
    public EntityManagerFactory entityManagerFactory() throws NamingException { 
     HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
     vendorAdapter.setGenerateDdl(false); 
     vendorAdapter.setShowSql(true); 
     LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); 
     factoryBean.setJpaVendorAdapter(vendorAdapter); 
     factoryBean.setPackagesToScan(EntityMarker.class.getPackage().getName()); 
     factoryBean.setDataSource(dataSource()); 
     factoryBean.afterPropertiesSet(); 
     return factoryBean.getObject(); 
    } 

    @Bean 
    public PlatformTransactionManager transactionManager() throws NamingException { 
     JpaTransactionManager transactionManager = new JpaTransactionManager(); 
     transactionManager.setEntityManagerFactory(entityManagerFactory()); 
     return transactionManager; 
    } 

    @Bean 
    public HibernateExceptionTranslator exceptionTranslator() { 
     return new HibernateExceptionTranslator(); 
    } 

    @Bean 
    public EmbeddedDatabase dataSource() { 
     EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); 
     return builder.setType(EmbeddedDatabaseType.H2).build(); 
    } 
} 

我遇到的问题是,虽然我的PersistenceTestConfiguration类应该实例化适当的存储库 - 他们是未来通过到服务类为空。

如果我手动@Mock测试类中的存储库,那么它们在服务中不再为空,但将总是返回null,例如调用.save(entity)方法。

我怀疑我正在做一些明显愚蠢的事情,但似乎无法弄清楚。

任何指针在正确的方向将受到赞赏。

编辑1:

最简单的可能测试

package <project>.cms.rest.test.service; 

import <project>.cms.rest.resource.PostalAddressResource; 
import <project>.cms.rest.service.PostalAddressService; 
import <project>.cms.rest.service.impl.PostalAddressServiceImpl; 
import <project>.cms.rest.test.configuration.PersistenceTestConfiguration; 
import liquibase.Liquibase; 
import liquibase.database.jvm.JdbcConnection; 
import liquibase.exception.LiquibaseException; 
import liquibase.resource.FileSystemResourceAccessor; 
import org.junit.After; 
import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.InjectMocks; 
import org.mockito.MockitoAnnotations; 
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.TestExecutionListeners; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 
import org.springframework.test.context.support.AnnotationConfigContextLoader; 
import org.springframework.transaction.annotation.Transactional; 
import org.springframework.util.Assert; 

import javax.inject.Inject; 
import java.sql.Connection; 

@Transactional 
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { PersistenceTestConfiguration.class }) 
@TestExecutionListeners(mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) 
public class PostalAddressServiceIntegrationTest { 

    @InjectMocks 
    private PostalAddressService postalAddressService = new PostalAddressServiceImpl(); 

    @Inject 
    private EmbeddedDatabase database; 

    @Before 
    public void setupDatabase() throws java.sql.SQLException, LiquibaseException { 
     MockitoAnnotations.initMocks(this); 

     Liquibase liquibase = new Liquibase(
       "src/liquibase/liquibase-master.xml", 
       new FileSystemResourceAccessor(), 
       new JdbcConnection(database.getConnection()) 
     ); 

     liquibase.update(""); 
    } 

    @After 
    public void tearDown() throws java.sql.SQLException, LiquibaseException { 
     Connection connection = database.getConnection(); 
     JdbcConnection liquibaseConnection = new JdbcConnection(connection); 

     Liquibase liquibase = new Liquibase(
       "src/liquibase/liquibase-master.xml", 
       new FileSystemResourceAccessor(), 
       liquibaseConnection 
     ); 

     liquibase.dropAll(); 
    } 

    @Test 
    public void testAddNewPostalAddress() { 
     PostalAddressResource postalAddressResource = new PostalAddressResource(); 

     postalAddressResource.setBuildingNameOrNumber("1"); 
     postalAddressResource.setFirstLine("Test Lane"); 
     postalAddressResource.setSecondLine("Testville"); 
     postalAddressResource.setCountry("Testshire"); 
     postalAddressResource.setPostCode("TE5 7ER"); 
     postalAddressResource.setCountry("United Kingdom"); 

     PostalAddressResource result = postalAddressService.createPostalAddress(postalAddressResource); 

     Assert.notNull(result); 
    } 
} 

所得堆栈跟踪

java.lang.NullPointerException 
    at <project>.cms.rest.service.impl.PostalAddressServiceImpl.createPostalAddress(PostalAddressServiceImpl.java:66) 
    at <project>.cms.rest.test.service.PostalAddressServiceIntegrationTest.testAddNewPostalAddress(PostalAddressServiceIntegrationTest.java:78) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) 
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193) 
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:606) 
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164) 
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110) 
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175) 
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107) 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68) 

线PostalAddressServiceImpl 66如下:

} while(repository.countByPublicId(publicId) > 0); 

编辑2:

创建测试与存储库,而不是通过服务工程直接工程,具有:

@Inject 
private PostalAddressRepository repository; 

在顶部行为本身。

所以它似乎是@InjectMocks应该是连接服务类的依赖关系有问题,导致存储库为空。

+0

没有堆栈跟踪,很难告诉任何事情。有一个方便吗?此外,它通常有助于打破再生的例子,以确保它不是在这里引起问题的数十件中的一件。简单的存储库引导程序(没有所有的安全性,服务等)是否会导致相同的问题? –

+0

@OliverGierke堆栈跟踪只是简单地显示服务使用的存储库在调用方法时是空的。 Spring代码中没有任何内容。我会尽量缩小这个范围到一个单一的工作例子,但没有其他的东西可以去除 –

+0

我很抱歉,但没有进一步的信息或更简单的例子,很难找出哪里出了问题,因为它实际上可能是任何东西。 –

回答

2

望着我得走了类似的东西是什么,我也有这样定义的

@ContextConfiguration(loader = AnnotationConfigContextLoader.class, 

和一些测试听众装载机

@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class}) 

集成测试是在Spring有点乱但在Spring Boot 1中已经整理好了很多。4:

https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4

+0

感谢您 - 已尝试使用这些注释中的每一个,但单独无效。刚刚尝试过,并且服务中的存储库仍为空。我应该@嘲笑仓库(我怀疑不是)?可悲的是,这个项目还没有转移到Spring Boot的位置。 –

+0

您正在配置的配置是否有像@EnableJpaRepositories这样的东西? – PaulNUK

+1

我的配置包含在我原来的文章中 - 我在顶部有这些注释:配置,EnableTransactionManagement,EnableJpaRepositores和现在的TestExecutionListeners –