mercredi 27 avril 2016

Attempting to perform Integration Test with Spring Data JPA Repositories returns NullPointerException

I am trying to write integration tests for a Spring 4 MVC project. In the project I am using Spring Data JPA Repositories and Hibernate.

Below are two files, the Integration Test itself and the Configuration for setting up my Persistence configuration.

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();
    }

    @Bean
    public StandardPBEStringEncryptor stringEncryptor() {
        String encryptionMasterPassword = System.getProperty("jaspyt.password", "testonly-password");

        StandardPBEStringEncryptor stringEncryptor = new StandardPBEStringEncryptor();
        stringEncryptor.setPassword(encryptionMasterPassword);

        HibernatePBEEncryptorRegistry registry = HibernatePBEEncryptorRegistry.getInstance();

        registry.registerPBEStringEncryptor("STRING_ENCRYPTOR", stringEncryptor);

        return stringEncryptor;
    }
}

ProjectServiceIntegrationTest.java

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

import <project>.cms.rest.enumeration.ProjectStatus;
import <project>.cms.rest.resource.CustomerResource;
import <project>.cms.rest.resource.PostalAddressResource;
import <project>.cms.rest.resource.ProjectResource;
import <project>.cms.rest.service.*;
import <project>.cms.rest.service.impl.ContactServiceImpl;
import <project>.cms.rest.service.impl.CustomerServiceImpl;
import <project>.cms.rest.service.impl.PostalAddressServiceImpl;
import <project>.cms.rest.service.impl.ProjectServiceImpl;
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.*;
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.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

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

@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { PersistenceTestConfiguration.class })
public class ProjectServiceIntegrationTest {

    @InjectMocks
    private ContactService contactService = new ContactServiceImpl();

    @InjectMocks
    private PostalAddressService postalAddressService = new PostalAddressServiceImpl();

    @InjectMocks
    private ProjectService projectService = new ProjectServiceImpl();

    @InjectMocks
    private CustomerService customerService = new CustomerServiceImpl();

    private CustomerResource dbCustomer;
    private PostalAddressResource dbPostalAddress;

    @Inject
    private EmbeddedDatabase dataSource;

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

        Connection connection = dataSource.getConnection();
        JdbcConnection liquibaseConnection = new JdbcConnection(connection);

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

        liquibase.update("");

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

        dbPostalAddress = postalAddressService.createPostalAddress(dbPostalAddress);

        dbCustomer = new CustomerResource();
        dbCustomer.setSiteAddress(dbPostalAddress);
        dbCustomer.setContactAddress(dbPostalAddress);
        dbCustomer.setBillingAddress(dbPostalAddress);
        dbCustomer.setName("Test Customer");

        dbCustomer = customerService.createCustomer(dbCustomer);
    }

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

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

        liquibase.dropAll();
    }

    @Test
    public void testProjectCount() {
        Assert.assertTrue(projectService.countAllProjects() == 0);
    }

    @Test
    public void testAddNullProject() {
        ProjectResource result = projectService.createProject(null);

        Assert.assertNull(result);
    }

    @Test
    public void testAddProjectWithNoCustomer() {
        ProjectResource newProject = new ProjectResource();

        newProject.setOrderNumber("abc123");
        newProject.setQuoteNumber("123/45");
        newProject.setChargeable(true);
        newProject.setGrossValue(12000L);
        newProject.setNetValue(10000L);
        newProject.setStatus(ProjectStatus.PROVISIONAL);
        newProject.setCustomer(null);

        ProjectResource result = projectService.createProject(newProject);

        Assert.assertNull(result);
    }

    @Test
    public void testAddProject() {
        ProjectResource newProject = new ProjectResource();

        newProject.setOrderNumber("abc123");
        newProject.setQuoteNumber("123/45");
        newProject.setChargeable(true);
        newProject.setGrossValue(12000L);
        newProject.setNetValue(10000L);
        newProject.setStatus(ProjectStatus.PROVISIONAL);
        newProject.setCustomer(dbCustomer);

        ProjectResource result = projectService.createProject(newProject);

        Assert.assertNotNull(result);
    }
}

The issue I'm having is that although my PersistenceTestConfiguration class should be instantiating the appropriate Repositories - they are coming through into the service classes as null.

If I manually @Mock the repositories in the Test Class then they are no longer null in the services, but will always return null on for example calling the .save(entity) method.

I suspect I'm doing something obviously stupid but can't seem to figure it out.

Any pointers in the right direction would be kindly appreciated.

Aucun commentaire:

Enregistrer un commentaire