单元测试中的 Spring Boot 数据源
Posted
技术标签:
【中文标题】单元测试中的 Spring Boot 数据源【英文标题】:Spring Boot Datasource in unit tests 【发布时间】:2018-09-08 14:17:31 【问题描述】:我有一个简单的 Spring Boot Web 应用程序,它从数据库中读取数据并返回 JSON 响应。我有以下测试配置:
@RunWith(SpringRunner.class)
@SpringBootTest(classes=MyApplication.class, properties="spring.config.name=myapp")
@AutoConfigureMockMvc
public class ControllerTests
@Autowired
private MockMvc mvc;
@MockBean
private ProductRepository productRepo;
@MockBean
private MonitorRepository monitorRepo;
@Before
public void setupMock()
Mockito.when(productRepo.findProducts(anyString(), anyString()))
.thenReturn(Arrays.asList(dummyProduct()));
@Test
public void expectBadRequestWhenNoParamters() throws Exception
mvc.perform(get("/products"))
.andExpect(status().is(400))
.andExpect(jsonPath("$.advice.status", is("ERROR")));
//other tests
我有一个在应用程序的主配置中配置的 DataSource bean。当我运行测试时,Spring 尝试加载上下文并失败,因为数据源来自 JNDI。一般来说,我想避免为此测试创建数据源,因为我已经模拟了存储库。
运行单元测试时是否可以跳过数据源的创建?
在内存数据库中进行测试不是一个选项,因为我的数据库创建脚本具有特定的结构,无法从 classpath:schema.sql 轻松执行
编辑
数据源定义在MyApplication.class
@Bean
DataSource dataSource(DatabaseProeprties databaseProps) throws NamingException
DataSource dataSource = null;
JndiTemplate jndi = new JndiTemplate();
setJndiEnvironment(databaseProps, jndi);
try
dataSource = jndi.lookup(databaseProps.getName(), DataSource.class);
catch (NamingException e)
logger.error("Exception loading JNDI datasource", e);
throw e;
return dataSource;
【问题讨论】:
您的数据源是否通过自动配置进行配置? @wjans 不,它是主配置中的一个 bean。查看我的编辑。 你不能简单地将数据源添加为@MockBean DataSource dataSource
吗?认为它的优点是您的生产代码执行 JNDI 查找甚至不会被执行。
【参考方案1】:
尝试将您的数据源也添加为@MockBean
:
@MockBean
private DataSource dataSource
这样,Spring 将为您执行替换逻辑,其优势是您的生产代码 bean 创建甚至不会被执行(没有 JNDI 查找)。
【讨论】:
这也是我的做法。您可以将 MockBean 添加到TestConfig.class
以最大程度地减少代码重复。
很好的建议,在测试类中添加 @MockBean(name = "your bean name")【参考方案2】:
由于您正在加载配置类 MyApplication.class
数据源 bean 将被创建,请尝试将数据源移动到另一个未用于测试的 bean 中,确保为测试加载的所有类不依赖于数据源。 或 在您的测试中创建一个标有@TestConfiguration
的配置类,并将其包含在SpringBootTest(classes=TestConfig.class)
模拟数据源中,例如
@Bean
public DataSource dataSource()
return Mockito.mock(DataSource.class);
但这可能会失败,因为对该模拟数据源的连接方法调用将返回 null,在这种情况下,您必须创建一个内存数据源,然后模拟 jdbcTemplate 和其余依赖项。
【讨论】:
很方便,谢谢。在日志中添加 TestConfiguration 后,我得到:Overriding bean definition for bean 'dataSource' with a different definition
。我还为集成测试创建了另一个定义真实数据源的 TestConfiguration。
这不会有潜在的风险,即覆盖将以不同的顺序发生吗?认为依赖这个不是一个好主意,认为你应该给模拟的 bean 一个不同的名字,并用 @Primary
注释它以确保。仍然有两个bean都会被创建的缺点。
我同意@wjans以上是关于单元测试中的 Spring Boot 数据源的主要内容,如果未能解决你的问题,请参考以下文章