9

I have the following table (migration):

databaseChangeLog:
  - changeSet:
      id: 1
      author: me
      changes:
        - createTable:
            tableName: person
            columns:
              - column:
                  name: id
                  type: int
                  autoIncrement: true
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: first_name
                  type: varchar(255)
                  constraints:
                    nullable: false
              - column:
                  name: last_name
                  type: varchar(255)
                  constraints:
                    nullable: false
  - changeSet:
      id: 2
      author: me
      changes:
        - insert:
            tableName: person
            columns:
              - column:
                  name: first_name
                  value: First
              - column:
                  name: last_name
                  value: Last

And the following DAO:

public interface HelloDao {
    @SqlQuery(
            "SELECT * FROM person"
    )
    @Mapper(PersonMapper.class)
    Person getPerson();
}

With the following entities + mapper:

public class Person {
    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

-

public class PersonMapper implements ResultSetMapper<Person> {
    public Person map(int index, ResultSet r, StatementContext ctx) throws SQLException {
        return new Person(r.getString("first_name"), r.getString("last_name"));
    }
}

I'm using junit and unitils to write a unit test for this Dao. I have the unitils.properties file set up like so:

database.driverClassName=org.postgresql.Driver
database.url=jdbc:postgresql://localhost:5432/springbootdb
database.dialect=postgresql
database.userName=<username>
database.password=<password>
database.schemaNames=public

Just for clarity, this my application.properties file:

spring.thymeleaf.cache=false
spring.main.show-banner=false
logging.level.jdbc=OFF
logging.level.jdbc.sqltiming=DEBUG
logging.level.jdbc.resultsettable=DEBUG

spring.datasource.url= jdbc:postgresql://localhost:5432/springbootdb
spring.datasource.username=<username> 
spring.datasource.password=<password>
spring.jpa.hibernate.ddl-auto=create-drop

Here is my test:

@Transactional(TransactionMode.ROLLBACK)
@RunWith(UnitilsBlockJUnit4ClassRunner.class)
public class HelloDaoTest {
    @TestDataSource
    DataSource dataSource;

    private DBI dbi;
    private HelloDao helloDao;

    @Before
    public void setUp() throws Exception {
        dbi = new DBI(dataSource);
        helloDao = dbi.onDemand(HelloDao.class);
    }

    @Test
    @DataSet("HelloDaoTest.testSet.xml")
    public void helloDao() throws Exception {
        Person p = helloDao.getPerson();
        assertEquals("First", p.getFirstName());
    }

}

And my fixture (HelloDaoTest.testSet.xml)

<?xml version="1.0" encoding="UTF-8" ?>
    <dataset>
        <person
            first_name="First"
            last_name="Last"
        />
    </dataset>

and the pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.experiment.springboot</groupId>
    <artifactId>testspringbootproj</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>Spring Boot Blank Project (from https://github.com/making/spring-boot-blank)</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <start-class>com.experiment.springboot.App</start-class>
        <java.version>1.8</java.version>
        <lombok.version>1.14.8</lombok.version>
        <log4jdbc.log4j2.version>1.16</log4jdbc.log4j2.version>
        <rest.assured.version>2.3.3</rest.assured.version>
        <jdbi.version>2.78</jdbi.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.jayway.restassured</groupId>
            <artifactId>rest-assured</artifactId>
            <version>${rest.assured.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.bgee.log4jdbc-log4j2</groupId>
            <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
            <version>${log4jdbc.log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4-1206-jdbc42</version>
        </dependency>
        <dependency>
            <groupId>org.jdbi</groupId>
            <artifactId>jdbi</artifactId>
            <version>${jdbi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.liquibase</groupId>
            <artifactId>liquibase-maven-plugin</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.unitils</groupId>
            <artifactId>unitils-dbunit</artifactId>
            <version>3.4.6</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <dependencies>
                    <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>springloaded</artifactId>
                        <version>${spring-loaded.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <plugin>
                <groupId>org.liquibase</groupId>
                <artifactId>liquibase-maven-plugin</artifactId>
                <version>3.4.1</version>
                <configuration>
                    <propertyFile>src/main/resources/liquibase.properties</propertyFile>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

When I run this test I get the following error:

java.lang.NullPointerException
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:820)
    at org.unitils.database.transaction.impl.DefaultUnitilsTransactionManager.rollback(DefaultUnitilsTransactionManager.java:157)
    at org.unitils.database.DatabaseModule.rollbackTransaction(DatabaseModule.java:425)
    at org.unitils.database.DatabaseModule.endTransactionForTestMethod(DatabaseModule.java:390)
    at org.unitils.database.DatabaseModule$DatabaseTestListener.afterTestTearDown(DatabaseModule.java:486)
    at org.unitils.core.Unitils$UnitilsTestListener.afterTestTearDown(Unitils.java:315)
    at org.unitils.core.junit.AfterTestTearDownStatement.evaluate(AfterTestTearDownStatement.java:48)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    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.unitils.core.junit.BeforeTestClassStatement.evaluate(BeforeTestClassStatement.java:41)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

It looks like the test code is not even reached. What am I doing wrong?

4
  • Not an expert on any of these techs, but if you look at the stack trace it looks as if the tests expect there to be some kind of transaction manager in a complete spring context, but that doesn't get set up (no spring junit runner). Commented May 17, 2017 at 6:13
  • please look at the second line of the test @RunWith(UnitilsBlockJUnit4ClassRunner.class) Commented May 17, 2017 at 6:16
  • 1
    Well, did you set up a Spring Application Context as described in unitils.sourceforge.net/tutorial-spring.html ? Commented May 17, 2017 at 6:19
  • yes i did this @TassosBassoukos Commented May 22, 2017 at 5:01

2 Answers 2

3
+50

You do have two database implementations in your pom.xml, without specifying scopes. Spring is not able to guess which one shall be the right one, hence an exception.

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
    [...]
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.4-1206-jdbc42</version>
    </dependency>

Most likely this will help you further: Configure specific in memory database for testing purpose in Spring

Sign up to request clarification or add additional context in comments.

Comments

2

I can't add a comment because of <50 rep. I thought maybe this would be useful.

Rollback transaction after @Test

It isn't using Unitils, but does seem to be the behavior that you are looking for. Unitils seems to have been last updated back in 2011 (and my suspicion is that is where your problem lies) so it might be worth junking it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.