使用 Unitils 对 Postgres 数据库运行单元测试时出现 NullPointerException
Posted
技术标签:
【中文标题】使用 Unitils 对 Postgres 数据库运行单元测试时出现 NullPointerException【英文标题】:NullPointerException while running unit test against Postgres database with Unitils 【发布时间】:2017-10-13 14:39:03 【问题描述】:我有下表(迁移):
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
还有以下 DAO:
public interface HelloDao
@SqlQuery(
"SELECT * FROM person"
)
@Mapper(PersonMapper.class)
Person getPerson();
使用以下实体+映射器:
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"));
我正在使用 junit 和 unitils 为这个 Dao 编写单元测试。我的unitils.properties
文件设置如下:
database.driverClassName=org.postgresql.Driver
database.url=jdbc:postgresql://localhost:5432/springbootdb
database.dialect=postgresql
database.userName=<username>
database.password=<password>
database.schemaNames=public
为了清楚起见,这是我的application.properties
文件:
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
这是我的测试:
@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());
还有我的固定装置 (HelloDaoTest.testSet.xml
)
<?xml version="1.0" encoding="UTF-8" ?>
<dataset>
<person
first_name="First"
last_name="Last"
/>
</dataset>
和 pom.xml 文件:
<?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>
当我运行此测试时,我收到以下错误:
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)
看起来测试代码甚至没有到达。我做错了什么?
【问题讨论】:
不是任何这些技术的专家,但是如果您查看堆栈跟踪,看起来好像测试期望在完整的 Spring 上下文中存在某种事务管理器,但事实并非如此t 设置好(没有 spring junit runner)。 请看第二行测试@RunWith(UnitilsBlockJUnit4ClassRunner.class)
那么,您是否按照unitils.sourceforge.net/tutorial-spring.html 中的描述设置了 Spring 应用程序上下文?
是的,我这样做了@TassosBassoukos
【参考方案1】:
您的 pom.xml 中确实有两个数据库实现,但没有指定范围。 Spring 无法猜测哪个是正确的,因此是一个例外。
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
[...]
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1206-jdbc42</version>
</dependency>
这很可能会进一步帮助您:Configure specific in memory database for testing purpose in Spring
【讨论】:
【参考方案2】:因为
Rollback transaction after @Test
它没有使用 Unitils,但似乎确实是您正在寻找的行为。 Unitils 似乎最后一次更新是在 2011 年(我怀疑这就是您的问题所在),因此可能值得将其丢弃。
【讨论】:
以上是关于使用 Unitils 对 Postgres 数据库运行单元测试时出现 NullPointerException的主要内容,如果未能解决你的问题,请参考以下文章
Unitils 与 Spring TestContext 框架
如何在 Postgres 中对数组列使用 BETWEEN 条件?