Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring-data-jpa bean validation in junit tests

In my recent work I've used spring-data-jpa to take advantage of provided repositories. When it came to integration tests I am unable to configure (I assume) spring context for testing and as a outcome bean validation doesn't work in my tests.

I am aware that I can inject validator, and unit test my annotations but it's not the case. I am writing integration tests and would like to test repositories with DB backed.

I have prepared simple project to show all necessary project files.

When I run tests, 2 are failing and I have no idea why, hibernate validator is present on class path.

Failed tests:   insertWrongEmail(com.example.core.data.jpa.UserRepositoryTest): Expected ConstraintViolationException wasn't thrown.
insertToShortPassword(com.example.core.data.jpa.UserRepositoryTest): Expected ConstraintViolationException wasn't thrown.

[..]

Apr 23, 2013 5:00:08 PM org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 4.3.1.Final

Source code and mvn test output below.

Thank you in advance for your help.

Java classes (I stripped of comments, geters, seters, equals, hashCode, toString etc.):

BaseEntity

package com.example.core.data.jpa;

import javax.persistence.*;

@MappedSuperclass
public abstract class BaseEntity {
    public static final String SEQUENCE = "global_seq";

    @Id
    @SequenceGenerator(name = SEQUENCE, sequenceName = SEQUENCE)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
    @Column(name = "id")
    private Long id;

    public Long getId() {
        return id;
    }
}

User

package com.example.core.data.jpa;

import javax.persistence.*;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
import java.util.List;

@Entity
@Table(name = "users")
@NamedQuery(name = "User.findByEmail", query = "select u from User u where upper(u.email) = :email")
public class User extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 333700989750828624L;

    private static final int MAX_NAME_LENGTH = 128;
    private static final int MAX_EMAIL_LENGTH = 128;
    private static final int MAX_PASSWORD_LENGTH = 256;
    private static final int MIN_NAME_LENGTH = 6;

    private static final int EQUALS_MAGIC = 71;

    @Size(min = MIN_NAME_LENGTH)    
    @Column(name = "name", nullable = false, length = MAX_NAME_LENGTH)
    private String name;

    @Pattern(regexp = "^([0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,9})$")
    @Column(name = "email", nullable = false, unique = true, length = MAX_EMAIL_LENGTH)
    private String email;

    @Column(name = "password", nullable = false, length = MAX_PASSWORD_LENGTH)
    private String password;

    @OneToMany(mappedBy="user", cascade={CascadeType.ALL}, fetch = FetchType.EAGER)
    private List<Role> roles;
//geters, seters, equals, hashCode
}

Role

package com.example.core.data.jpa;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "roles")
public class Role extends BaseEntity implements Serializable {
    private static final long serialVersionUID = -2575871700366265974L;

    private static final int MAX_NAME_LENGTH = 128;

    @Column(name = "name", nullable = false, unique = true, length = MAX_NAME_LENGTH)
    private String name;

    @ManyToOne(cascade={CascadeType.ALL})
    private User user;
//geters, seters, equals, hashCode
}

UserRepositoryTest

package com.example.core.data.jpa;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import com.example.core.data.repository.UserRepository;

import javax.inject.Inject;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:test-context.xml")
@Transactional
public class UserRepositoryTest {
    @Inject
    private UserRepository userRepository;

    private User user;

    private static final String NAME = "User Name";
    private static final String EMAIL = "[email protected]";
    private static final String PASSWORD = "PASSWORD";

    @Before
    public void setUp() {
        user = new User(NAME, EMAIL, PASSWORD);
    }

    @Test
    public void insert() {
        //given

        //when
        User inserted = userRepository.save(user);

        //then
        assertEquals(NAME, inserted.getName());
        assertEquals(EMAIL, inserted.getEmail());
        assertEquals(PASSWORD, inserted.getPassword());
        assertNotNull(inserted.getId());
    }

    @Test
    public void insertWrongEmail() {
        //given
        user.setEmail("NOT_AN_EMAIL_ADDRESS");

        //when
        try {
            userRepository.save(user);

            fail("Expected ConstraintViolationException wasn't thrown.");

        } catch (ConstraintViolationException e) {
            //then

            assertEquals(1, e.getConstraintViolations().size());
            ConstraintViolation<?> violation =
                    e.getConstraintViolations().iterator().next();

            assertEquals("email", violation.getPropertyPath().toString());
            assertEquals(Pattern.class,
                    violation.getConstraintDescriptor()
                            .getAnnotation().annotationType());
        }
    }

    @Test
    public void insertToShortName() {
        //given
        user.setName("SHORT");

        //when
        try {
            userRepository.save(user);

            fail("Expected ConstraintViolationException wasn't thrown.");

        } catch (ConstraintViolationException e) {
        //then

            assertEquals(1, e.getConstraintViolations().size());
            ConstraintViolation<?> violation =
                    e.getConstraintViolations().iterator().next();

            assertEquals("name", violation.getPropertyPath().toString());
            assertEquals(Size.class,
                    violation.getConstraintDescriptor()
                            .getAnnotation().annotationType());
        }
    }
}

UserRepository

package com.example.core.data.repository;

import org.springframework.data.repository.PagingAndSortingRepository;
import com.example.core.data.jpa.User;

public interface UserRepository extends PagingAndSortingRepository<User, Long> {
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>data-jpa</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>Exampl core jpa package</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.java-persistence</groupId>
            <artifactId>jpa-api</artifactId>
            <version>2.0-cr-1</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.3.1.Final</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.6.0</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.12</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>3.2.2.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>2.2.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

test-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa
            http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/jdbc
            http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
        http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

    <context:annotation-config/>
    <jpa:repositories base-package="com.example.core.data.repository" />
    <tx:annotation-driven transaction-manager="transactionManager" />

    <jdbc:embedded-database id="dataSource" type="HSQL"/>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
            p:entityManagerFactory-ref="entityManagerFactory" />

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
          p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter" >
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
        </property>
        <property name="packagesToScan">
            <list>
                <value>com.example.core.data.jpa</value>
            </list>
        </property>
    </bean>

    <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
          p:generateDdl="true" p:database="HSQL" />

    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"
            p:messageInterpolator-ref="messageInterpolator" p:validationMessageSource-ref="messageSource" />

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
          p:basename="classpath:I18N/messages,classpath:ValidationMessages*.properties" />

    <bean id="messageInterpolator"
          class="org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator" />
</beans>

mvn test output

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Example core jpa package 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ data-jpa ---
[debug] execute contextualize
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ data-jpa ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ data-jpa ---
[debug] execute contextualize
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ data-jpa ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.10:test (default-test) @ data-jpa ---
[INFO] Surefire report directory: /home/[..]/data-jpa/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.example.core.data.jpa.UserRepositoryTest
Apr 23, 2013 4:39:34 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [test-context.xml]
Apr 23, 2013 4:39:35 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.GenericApplicationContext@3cd6ad74: startup date [Tue Apr 23 16:39:35 CEST 2013]; root of context hierarchy
Apr 23, 2013 4:39:35 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Apr 23, 2013 4:39:35 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver#423dc560' of type [class org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Apr 23, 2013 4:39:35 PM org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory initDatabase
INFO: Creating embedded database 'dataSource'
Apr 23, 2013 4:39:35 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'dataSource' of type [class org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Apr 23, 2013 4:39:35 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'dataSource' of type [class org.springframework.jdbc.datasource.SimpleDriverDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Apr 23, 2013 4:39:35 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'jpaAdapter' of type [class org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Apr 23, 2013 4:39:35 PM org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean createNativeEntityManagerFactory
INFO: Building JPA container EntityManagerFactory for persistence unit 'default'
Apr 23, 2013 4:39:35 PM org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
Apr 23, 2013 4:39:35 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.2.0.Final}
Apr 23, 2013 4:39:35 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Apr 23, 2013 4:39:35 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Apr 23, 2013 4:39:35 PM org.hibernate.ejb.Ejb3Configuration configure
INFO: HHH000204: Processing PersistenceUnitInfo [
    name: default
    ...]
Apr 23, 2013 4:39:36 PM org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator instantiateExplicitConnectionProvider
INFO: HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
Apr 23, 2013 4:39:36 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
Apr 23, 2013 4:39:36 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
Apr 23, 2013 4:39:36 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Apr 23, 2013 4:39:36 PM org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 4.3.1.Final
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000228: Running hbm2ddl schema update
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000102: Fetching database metadata
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000396: Updating schema
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata
INFO: HHH000262: Table not found: roles
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata
INFO: HHH000262: Table not found: users
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata
INFO: HHH000262: Table not found: roles
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata
INFO: HHH000262: Table not found: users
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.DatabaseMetadata getTableMetadata
INFO: HHH000262: Table not found: global_seq
Apr 23, 2013 4:39:37 PM org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: HHH000232: Schema update complete
Apr 23, 2013 4:39:37 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'entityManagerFactory' of type [class org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Apr 23, 2013 4:39:37 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' of type [class org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Apr 23, 2013 4:39:37 PM org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'org.springframework.transaction.config.internalTransactionAdvisor' of type [class org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Apr 23, 2013 4:39:37 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@69950b4: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,userRepository,org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor#0,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0,org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor#0,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,dataSource,transactionManager,entityManagerFactory,jpaAdapter,validator,messageSource,messageInterpolator,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
Apr 23, 2013 4:39:38 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@58eac93b]; rollback [true]
Apr 23, 2013 4:39:38 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Rolled back transaction after test execution for test context [TestContext@2b98919b testClass = UserRepositoryTest, testInstance = com.example.core.data.jpa.UserRepositoryTest@2d7f6d79, testMethod = insert@UserRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@8ec3a45 testClass = UserRepositoryTest, locations = '{classpath:test-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
Apr 23, 2013 4:39:38 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (2): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@58eac93b]; rollback [true]
Apr 23, 2013 4:39:38 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Rolled back transaction after test execution for test context [TestContext@2b98919b testClass = UserRepositoryTest, testInstance = com.example.core.data.jpa.UserRepositoryTest@1fcf7061, testMethod = insertWrongEmail@UserRepositoryTest, testException = java.lang.AssertionError: Expected ConstraintViolationException wasn't thrown., mergedContextConfiguration = [MergedContextConfiguration@8ec3a45 testClass = UserRepositoryTest, locations = '{classpath:test-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
Apr 23, 2013 4:39:38 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (3): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@58eac93b]; rollback [true]
Apr 23, 2013 4:39:38 PM org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Rolled back transaction after test execution for test context [TestContext@2b98919b testClass = UserRepositoryTest, testInstance = com.example.core.data.jpa.UserRepositoryTest@168ee2a9, testMethod = insertToShortPassword@UserRepositoryTest, testException = java.lang.AssertionError: Expected ConstraintViolationException wasn't thrown., mergedContextConfiguration = [MergedContextConfiguration@8ec3a45 testClass = UserRepositoryTest, locations = '{classpath:test-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
Tests run: 3, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 3.712 sec <<< FAILURE!

Results :

Failed tests:   insertWrongEmail(com.example.core.data.jpa.UserRepositoryTest): Expected ConstraintViolationException wasn't thrown.
  insertToShortPassword(com.example.core.data.jpa.UserRepositoryTest): Expected ConstraintViolationException wasn't thrown.

Tests run: 3, Failures: 2, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.216s
[INFO] Finished at: Tue Apr 23 16:39:38 CEST 2013
[INFO] Final Memory: 7M/245M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.10:test (default-test) on project data-jpa: There are test failures.
[ERROR] 
[ERROR] Please refer to /home/[..]/data-jpa/target/surefire-reports for the individual test results.
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

Process finished with exit code 1

Solved

After answer from @gunnar, I have change test to flush persistence context after repository.save and it works as expected.

Changes to UserRepository

//inject entity manager
@PersistenceContext
private EntityManager entityManager;

//add flush after save in test method
@Test
public void insertWrongEmail() {
    //given
    user.setEmail("NOT_AN_EMAIL_ADDRESS");

    //when
    try {
        userRepository.save(user);
        entityManager.flush();

        fail("Expected ConstraintViolationException wasn't thrown.");

Solution 2

After recommendation from @andyb I have switched to eclipselink and tests work without flushing. That's the solution I will go with in my opinion it's better to switch implementation than using workaround.

like image 565
pejas Avatar asked Apr 23 '13 15:04

pejas


1 Answers

I managed to reproduce the problem exactly described in the question locally, albeit after adding back the missing get/set functions and the UserRepository class :-)

After some digging I found two existing questions JPA ConstraintViolation vs Rollback and Hibernate not following JPA specifications when combined with Bean Validation API?

Both seem to conclude that Hibernate is not throwing the ConstraintValidationException correctly.

The outcome of the second question was a defect HHH-8028 - entityManager.persist not throwing ConstraintValidationException being raised against Hibernate.

To confirm this was the same issue, I switched to a simple @GeneratedValue and insertWrongEmail passed. insertToShortPassword was still failing but I put that down to a missing @Size(min = 6) on the password field. After adding that, all tests passed.

Reverting back to your configured @GeneratedValue I then swapped Hibernate for the EclipseLink persistence framework. Both tests passed which seems to confirm the discovery from the previous questions. The changes I made were:

pom.xml changes add the jpa artifact as described on the EclipseLink site

<dependency>
   <groupId>org.eclipse.persistence</groupId>
   <artifactId>org.eclipse.persistence.jpa</artifactId>
   <version>2.4.0</version>
   <scope>compile</scope>
</dependency>

test-context.xml changes

Switch to EclipseLinkJpaVendorAdapter

<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"
    p:generateDdl="true" p:database="HSQL" />

Add eclipselink.weaving property, as detailed on EclipseLinkJpaVendorAdapter instead of HibernateJpaVendorAdapter issue

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter" >
    <!-- existing configuration is identical -->
    <property name="jpaPropertyMap">
      <map>
        <entry key="eclipselink.weaving" value="false"/>
      </map>
    </property>
</bean>

User.java changes

I needed to add a default no-argument constructor. You might already have one in the full User.java class.

like image 190
andyb Avatar answered Oct 11 '22 09:10

andyb