2016-04-27 9 views
2

Я пытаюсь написать интеграционные тесты для проекта Spring 4 MVC. В проекте я использую Spring Data JPA Repositories и Hibernate.Попытка выполнить интеграционный тест с данными Spring Data JPA Repositories возвращает NullPointerException

Ниже приведены два файла - сам тест интеграции и конфигурация для настройки моей конфигурации Persistence.

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 репозитории в тестовом классе, то они больше не являются нулевыми в службах, но всегда будут возвращать нуль, например, для вызова метода .save (entity).

Я подозреваю, что я делаю что-то явно глупое, но, похоже, не могу понять.

Любые указатели в правильном направлении были бы любезны.

Edit 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) 

линии 66 из PostalAddressServiceImpl выглядит следующим образом:

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

Edit 2:

Создание теста, который работает непосредственно с репозиторием, а не с помощью службы работает, имея:

@Inject 
private PostalAddressRepository repository; 

на вершине ведет себя.

Похоже, что @InjectMocks должен подключаться к зависимостям класса Service, что есть проблема, в результате чего репозиторий имеет значение null.

+0

Без трассировки стека трудно сказать что-либо. Имейте один удобный? Кроме того, обычно это помогает сломать пример воспроизведения, чтобы убедиться, что это не одна из десятков штук, которые здесь играют, что вызывает проблему. Эта проблема возникает при загрузке в простой загрузочной репозитории (без всякой безопасности, услуг и т. Д.)? –

+0

@OliverGierke Трассировка стека просто показывает, что репозиторий, используемый службой, является нулевым, когда я вызываю метод на нем. Ничего в коде Spring нет. Я попытаюсь сузить это до одного рабочего примера, но больше нечего раскрыть. –

+0

Извините, но без дополнительной информации или более сжатого примера трудно понять, что происходит не так, как это может быть практически что-нибудь. –

ответ

1

Эта проблема была решена в соответствии с:

https://tedvinke.wordpress.com/2014/02/13/mockito-why-you-should-not-use-injectmocks-annotation-to-autowire-fields/

Изменение свои услуги, чтобы иметь конструкторами принимать в зависимости, а не в надежде @InjectMocks будет делать эту работу он, как предполагается вместо этого.

2

Глядя на то, что я должен запустить что-то подобное, я и грузчик определяется как этот

@ContextConfiguration(loader = AnnotationConfigContextLoader.class, 

и некоторых тестовых слушатели

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

тестирование интеграции немного грязное весной но был убран много в Весеннем Boot 1.4:

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

+0

Спасибо за это - попытался использовать каждую из этих аннотаций, но отдельно безрезультатно. Только что попробовали, и хранилища по-прежнему недействительны в Сервисах. Должен ли я быть @ Mock'ing репозиториев (я подозреваю, нет)? К сожалению, пока не удается перейти к Spring Boot. –

+0

У вас есть конфигурация, которую вы пытаетесь получить, например, @EnableJpaRepositories? – PaulNUK

+1

У меня есть конфигурация, включенная в мой оригинальный пост. У меня есть эти аннотации вверху: Конфигурация, EnableTransactionManagement, EnableJpaRepositores и теперь TestExecutionListeners –

Смежные вопросы