当我们在Java项目中,使用dbunit做UT测试时,有可能会发生下面AmbiguousTableNameException的错误。
UT测试类代码:
@SpringBootTest(classes = ServiceTestApplication.class)
@ActiveProfiles("test")
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
MockitoTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@ComponentScan(value = "com.xxxx")
@AutoConfigureMockMvc
public class TestControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
@DatabaseSetup(value = { "classpath:com/test_102N.xls" })
@DatabaseTearDown(value = { "classpath:databaseTearDown/DatabaseTearDown.xls" })
void test_102N() throws Exception {
// ヘッダーの情報の設定
org.springframework.http.HttpHeaders headers = new HttpHeaders();
headers.add("x-user-id", "123");
headers.add("x-system-id", "456");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.put("testKbn", Collections.singletonList("1"));
// リクエストを実行する
MvcResult mvcResult = mockMvc.perform(get("/test").queryParams(params).headers(headers)).andReturn();
String actualContent = mvcResult.getResponse().getContentAsString(Charset.forName("UTF-8"));
// リターンステータスが正しいかどうかを判断する
int status = mvcResult.getResponse().getStatus();
assertEquals(HttpStatus.OK.value(), status);
}
}
application-test.yaml:
注意:这里用jdbc:postgresql://localhost:5432/postgres?currentSchema=ut_db 指定连接的Schema不起作用
spring.datasource:
url: jdbc:postgresql://localhost:5432/postgres
username: dummy
password: dummyvalue
driver-class-name: org.postgresql.Driver
spring.main.allow-circular-references: true
logging:
level:
com.jtb.nucleus: debug
异常信息:

分析原因
当一个实例下存在多个数据库,而且这个数据库中存在相同名称的表,Dbunit会报一个不能区分是哪个表的错误。
在数据库中存在两个同名的数据表,同名->不区分大小写的同名,比如user和USER也是同名的,特别的是这两个同名数据表可能是存在本地中两个不同的Schema中。
在没有指定Schema的情况下,DbUnit会默认扫描整个实例。

解决方法
- 重命名你当前项目的数据表,使其不与数据库中其他数据表重名,如user命名为t_user。
- 删除其他数据库中的重名数据表,使你当前数据表命名唯一。
- 假如在连接数据库时未指定到哪个具体的schema,那么就指定schema。
指定schema的例子
创建db连接Configuration类(注意TestConfiguration注解,因为该配置只想在Test类有效)
package com.xxx.config;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.springtestdbunit.bean.DatabaseConfigBean;
import com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean;
//@Configuration
@TestConfiguration
public class DbUnitConfig {
@Bean("dbUnitConnection")
DatabaseDataSourceConnectionFactoryBean getTestConnection(DataSource dataSource) {
DatabaseDataSourceConnectionFactoryBean bean = new DatabaseDataSourceConnectionFactoryBean();
bean.setDataSource(dataSource);
DatabaseConfigBean databaseConfigBean = new DatabaseConfigBean();
databaseConfigBean.setAllowEmptyFields(true);
bean.setDatabaseConfig(databaseConfigBean);
bean.setSchema("ut_db");
return bean;
}
}
在测试类通过DbUnitConfiguration指定数据源
@SpringBootTest(classes = ServiceTestApplication.class)
@ActiveProfiles("test")
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
MockitoTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@ComponentScan(value = "com.xxxx")
@AutoConfigureMockMvc
@DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class, databaseConnection = { "dbUnitConnection" })
public class TestControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
@DatabaseSetup(value = { "classpath:com/test_102N.xls" })
@DatabaseTearDown(value = { "classpath:databaseTearDown/DatabaseTearDown.xls" })
void test_102N() throws Exception {
// ヘッダーの情報の設定
org.springframework.http.HttpHeaders headers = new HttpHeaders();
headers.add("x-user-id", "123");
headers.add("x-system-id", "456");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.put("testKbn", Collections.singletonList("1"));
// リクエストを実行する
MvcResult mvcResult = mockMvc.perform(get("/test").queryParams(params).headers(headers)).andReturn();
String actualContent = mvcResult.getResponse().getContentAsString(Charset.forName("UTF-8"));
// リターンステータスが正しいかどうかを判断する
int status = mvcResult.getResponse().getStatus();
assertEquals(HttpStatus.OK.value(), status);
}
}
补充
另外,DbUnitConfig作为TestConfiguration,会在测试类启动时被扫描加载,会创建 @Bean(“dbUnitConnection”),但是这个Bean需要创建一个DataSource dataSource连接,但是假如我们的测试工程不需要连接数据库,而没有设置数据库的配置,启动测试类时会导致出下面的错误。
Description: Parameter 0 of method getTestConnection in DbUnitConfig required a bean of type 'javax.sql.DataSource' that could not be found. Action: Consider defining a bean of type 'javax.sql.DataSource' in your configuration.
解决方法是我们可以在测试类加上,来mock一个DataSource
@MockBean DataSource dataSource;
完整代码
@SpringBootTest(classes = ServiceTestApplication.class)
@ActiveProfiles("test")
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
MockitoTestExecutionListener.class,
DbUnitTestExecutionListener.class })
@ComponentScan(value = "com.xxxx")
@AutoConfigureMockMvc
@DbUnitConfiguration(dataSetLoader = XlsDataSetLoader.class, databaseConnection = { "dbUnitConnection" })
public class TestControllerTest {
// 这部分很重要
@MockBean
DataSource dataSource;
@Autowired
private MockMvc mockMvc;
@Test
@DatabaseSetup(value = { "classpath:com/test_102N.xls" })
@DatabaseTearDown(value = { "classpath:databaseTearDown/DatabaseTearDown.xls" })
void test_102N() throws Exception {
// ヘッダーの情報の設定
org.springframework.http.HttpHeaders headers = new HttpHeaders();
headers.add("x-user-id", "123");
headers.add("x-system-id", "456");
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.put("testKbn", Collections.singletonList("1"));
// リクエストを実行する
MvcResult mvcResult = mockMvc.perform(get("/test").queryParams(params).headers(headers)).andReturn();
String actualContent = mvcResult.getResponse().getContentAsString(Charset.forName("UTF-8"));
// リターンステータスが正しいかどうかを判断する
int status = mvcResult.getResponse().getStatus();
assertEquals(HttpStatus.OK.value(), status);
}
}