1

I'm using Hibernate and Spring Data to model a very simple domain:

@Entity
public class User implements Serializable {

    private static final long serialVersionUID = -5501812656863255674L;

    @Id
    private String emailAddress;

    @Column
    private String forename;

    @Column
    private String surname;

    @Column
    @Enumerated(EnumType.STRING)
    private UserRole role;

    @OneToMany(cascade = { CascadeType.ALL })
    private List<Team> teams;
}

and

@Entity
public class Team implements Serializable {

    private static final long serialVersionUID = -3734641391628154428L;

    private static final BigDecimal STARTING_BUDGET = new BigDecimal(100);

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(unique = true)
    private String name;
}

I then have an 'updateUser' method in a data service which does as it is named. The idea is that to add a Team to a User, this method would be used and the cascading would result in the Team being persisted in the database.

@Override
    public void updateUser(final User user) throws IntegrationException {

        if (userRepository.exists(user.getEmailAddress())) {
            userRepository.save(user);
        } else {
            throw new IntegrationException(IntegrationExceptionCode.USER_NOT_FOUND);
        }
    }

I'm then unit testing this method using a HSQLDB database and Spring DBUnit to setup the initial database contents and the expected DB contents:

Initial DB Content Config

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <User emailAddress="user1@test.com" forename="User" surname="One" role="MANAGER" />
    <Player />
    <User_Team />
    <Team />
</dataset>

Expected DB Content Config

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <User emailAddress="user1@test.com" forename="User" surname="One" role="MANAGER" />
    <Player />
    <Team id="1" name="Test Team" totalScore="0" status="INCOMPLETE" remainingBudget="100" />
    <User_Team User_emailAddress="user1@test.com" Teams_id="1" />
</dataset>

I then have two tests: one which tests the update success; one which tests that a user which is not already in the system can't be updated.

Success Test

@Test
@ExpectedDatabase("UserData-WithTeam.xml")
public void testUpdateUser_AddedTeam_Success() throws Exception {
    // arrange
    final User user = UserTestDataBuilder.aManager(VALID_EMAIL_ADDRESS, "User", "One").withTeam().build();

    // act
    userDataService.updateUser(user);

    // assert - done by @ExpectedDatabase annotation
}

'User Does Not Exist' Test

@Test
    public void testUpdateUser_AddedTeam_UserDoesNotExist() throws Exception {
        // arrange
        thrownException.expect(IntegrationException.class);
        thrownException.expect(CustomIntegrationExceptionMatcher.hasCode(IntegrationExceptionCode.USER_NOT_FOUND));

        final User user = UserTestDataBuilder.aManagerWithEmailAddress(INVALID_EMAIL_ADDRESS).withTeam().build();

        // act
        userDataService.updateUser(user);

        // assert
        Assert.fail("Exception expected");
    }

The 'success' test works fine. However, the 'failure case' test errors with the following error:

java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action; FK_RVG5KHM9RO439HI17HPAUV5KG table: USER_TEAM
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.JDBCStatement.execute(Unknown Source)
    at org.dbunit.database.statement.SimpleStatement.executeBatch(SimpleStatement.java:69)
    at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:126)
    at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
    at com.github.springtestdbunit.DbUnitRunner.setupOrTeardown(DbUnitRunner.java:194)
    at com.github.springtestdbunit.DbUnitRunner.beforeTestMethod(DbUnitRunner.java:66)
    at com.github.springtestdbunit.DbUnitTestExecutionListener.beforeTestMethod(DbUnitTestExecutionListener.java:186)
    at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:249)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hsqldb.HsqlException: integrity constraint violation: foreign key no action; FK_RVG5KHM9RO439HI17HPAUV5KG table: USER_TEAM
    at org.hsqldb.error.Error.error(Unknown Source)
    at org.hsqldb.StatementDML.performReferentialActions(Unknown Source)
    at org.hsqldb.StatementDML.delete(Unknown Source)
    at org.hsqldb.StatementDML.executeDeleteStatement(Unknown Source)
    at org.hsqldb.StatementDML.getResult(Unknown Source)
    at org.hsqldb.StatementDMQL.execute(Unknown Source)
    at org.hsqldb.Session.executeCompiledStatement(Unknown Source)
    at org.hsqldb.Session.executeDirectStatement(Unknown Source)
    at org.hsqldb.Session.execute(Unknown Source)
    ... 32 more

It seems to be suggesting that it can't tear down the test data added in the 'success' test (and I've added the @Ignore annotation to the success test and the failure test passes). My question is why? My cascade on the @OneToMany relationship is set to ALL so all entities saved as part of the User-Team relationship should be removed.

Does anyone have any ideas?

chrishern
  • 302
  • 2
  • 6
  • 15

1 Answers1

0

I think you have a Integrity constraint in USER_TEAM table: UPDATE NO ACTION that's why gives java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no action;