如何从 Junit5 的配置中获取 DataSource bean
How to get DataSource bean from config in the Junit5
亲爱的,
我已经创建了一个 junit5 测试用例 (UserDaoTests.java),但我无法获得在 spring 配置文件 (data.xml) 中定义的 DataSource Bean。
项目结构:
测试用例在 test/com/caveofprogramming/spring/test/tests 包中定义,UserDaoTests.java class。
data.xml
junit 的配置文件。我在其中定义了数据源 bean。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan
base-package="com.caveofprogramming.spring.test.tests">
</context:component-scan>
<context:annotation-config></context:annotation-config>
<mvc:annotation-driven></mvc:annotation-driven>
<context:property-placeholder
location="test/com/caveofprogramming/spring/test/config/jdbc.properties" />
<beans profile="dev">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="username" value="${jdbc.username}"></property>
</bean>
</beans>
</beans>
jdbc.properties:
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = TESTD01)))
jdbc.password=1234
jdbc.username=offerTest
联合测试(UserDaoTests.java)
package com.caveofprogramming.spring.test.tests;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import com.offers.DAO.UserDAO;
@ActiveProfiles("dev")
@ContextConfiguration(locations = {
"classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
public class UserDaoTests {
@Autowired
private UserDAO userDao;
private static DataSource dataSource;
private JdbcTemplate jdbc;
@Autowired
public UserDaoTests() {
ApplicationContext context = new FileSystemXmlApplicationContext("test/com/caveofprogramming/spring/test/config/data.xml");
this.dataSource = (DataSource) context.getBean("dataSource");
}
@Test
public void testCreateUser() {
if ( dataSource == null) {
System.out.println("DataSource is null");
}
else {
System.out.println("DataSource is not null!!!! ");
}
}
}
日志:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'dataSource' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:816)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1288)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
我还想澄清一下,我使用的是静态数据源,因为我需要使用@BeforeAll,它只需要静态字段。
我也测试了非静态数据源,但结果还是一样。
--更新----
我从 data.xml 配置文件中删除了 <beans profile="dev">
标签,它工作正常。但是我不明白为什么它不能使用配置文件。
--- 更新 2(更新 Bhushan 的回答)-----
UserDaoTests - 更新代码
@ExtendWith(SpringExtension.class)
//Add all required depency xml
@ContextConfiguration(locations = { "classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
@ActiveProfiles("dev")
public class UserDaoTests {
@Autowired
private UserDAO userDao;
@Autowired
private DataSource dataSource;
@Autowired
private JdbcTemplate jdbc;
@Test
public void testCreateUser() {
Assertions.assertNotNull(dataSource);
// Assertions.assertNotNull(jdbc);
}
}
错误堆栈跟踪:
org.opentest4j.AssertionFailedError: expected: not <null>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:39)
at org.junit.jupiter.api.Assertions.fail(Assertions.java:109)
at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:47)
at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:36)
at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:31)
at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:283)
at com.caveofprogramming.spring.test.tests.UserDaoTests.testCreateUser(UserDaoTests.java:38)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:43)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:82)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:73)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:141)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
此处您正在创建多个应用程序上下文,一个是使用 @ContextConfiguration 创建的,另一个是使用 FileSystemXmlApplicationContext 创建的,因此请避免使用 FileSystemXmlApplicationContext 并进行更新您的代码如下
@ExtendWith(SpringExtension.class)
//Add all required depency xml
@ContextConfiguration(locations = {
"classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
@ActiveProfiles("dev")
public class UserDaoTests {
@Autowired
private UserDAO userDao;
@Autowired
private DataSource dataSource;
@Autowired
private JdbcTemplate jdbc;
@Test
public void testCreateUser() {
Assertions.assertNotNull(dataSource);
Assertions.assertNotNull(jdbc);
}
}
还要避免使用 @BeforeAll,因为它与静态内存相结合,而我们的 Bean 由 spring 管理,所以不能使用它,你可以用它代替你为 @BeforeEach 如果你想执行一些逻辑 你想要 运行 只对所有测试用例一次所以你可以做 hack 类似
private AtomicBoolean executed = new AtomicBoolean(false);
@BeforeEach
public void runOnce() {
if(!executed.getAndSet(true)) {
// write you logic which you want will run only once for all test cases
}
}
亲爱的,
我已经创建了一个 junit5 测试用例 (UserDaoTests.java),但我无法获得在 spring 配置文件 (data.xml) 中定义的 DataSource Bean。
项目结构:
测试用例在 test/com/caveofprogramming/spring/test/tests 包中定义,UserDaoTests.java class。
data.xml
junit 的配置文件。我在其中定义了数据源 bean。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan
base-package="com.caveofprogramming.spring.test.tests">
</context:component-scan>
<context:annotation-config></context:annotation-config>
<mvc:annotation-driven></mvc:annotation-driven>
<context:property-placeholder
location="test/com/caveofprogramming/spring/test/config/jdbc.properties" />
<beans profile="dev">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="username" value="${jdbc.username}"></property>
</bean>
</beans>
</beans>
jdbc.properties:
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = TESTD01)))
jdbc.password=1234
jdbc.username=offerTest
联合测试(UserDaoTests.java)
package com.caveofprogramming.spring.test.tests;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import com.offers.DAO.UserDAO;
@ActiveProfiles("dev")
@ContextConfiguration(locations = {
"classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
public class UserDaoTests {
@Autowired
private UserDAO userDao;
private static DataSource dataSource;
private JdbcTemplate jdbc;
@Autowired
public UserDaoTests() {
ApplicationContext context = new FileSystemXmlApplicationContext("test/com/caveofprogramming/spring/test/config/data.xml");
this.dataSource = (DataSource) context.getBean("dataSource");
}
@Test
public void testCreateUser() {
if ( dataSource == null) {
System.out.println("DataSource is null");
}
else {
System.out.println("DataSource is not null!!!! ");
}
}
}
日志:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'dataSource' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:816)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1288)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
我还想澄清一下,我使用的是静态数据源,因为我需要使用@BeforeAll,它只需要静态字段。
我也测试了非静态数据源,但结果还是一样。
--更新----
我从 data.xml 配置文件中删除了 <beans profile="dev">
标签,它工作正常。但是我不明白为什么它不能使用配置文件。
--- 更新 2(更新 Bhushan 的回答)-----
UserDaoTests - 更新代码
@ExtendWith(SpringExtension.class)
//Add all required depency xml
@ContextConfiguration(locations = { "classpath:test/com/caveofprogramming/spring/test/config/data.xml",
"classpath:com/offers/config/offerDAO-context.xml",
"classpath:com/offers/config/offerService-context.xml" })
@ActiveProfiles("dev")
public class UserDaoTests {
@Autowired
private UserDAO userDao;
@Autowired
private DataSource dataSource;
@Autowired
private JdbcTemplate jdbc;
@Test
public void testCreateUser() {
Assertions.assertNotNull(dataSource);
// Assertions.assertNotNull(jdbc);
}
}
错误堆栈跟踪:
org.opentest4j.AssertionFailedError: expected: not <null>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:39)
at org.junit.jupiter.api.Assertions.fail(Assertions.java:109)
at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:47)
at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:36)
at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:31)
at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:283)
at com.caveofprogramming.spring.test.tests.UserDaoTests.testCreateUser(UserDaoTests.java:38)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access0(ParentRunner.java:66)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:43)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:82)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:73)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:141)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
此处您正在创建多个应用程序上下文,一个是使用 @ContextConfiguration 创建的,另一个是使用 FileSystemXmlApplicationContext 创建的,因此请避免使用 FileSystemXmlApplicationContext 并进行更新您的代码如下
@ExtendWith(SpringExtension.class) //Add all required depency xml @ContextConfiguration(locations = { "classpath:test/com/caveofprogramming/spring/test/config/data.xml", "classpath:com/offers/config/offerDAO-context.xml", "classpath:com/offers/config/offerService-context.xml" }) @ActiveProfiles("dev") public class UserDaoTests { @Autowired private UserDAO userDao; @Autowired private DataSource dataSource; @Autowired private JdbcTemplate jdbc; @Test public void testCreateUser() { Assertions.assertNotNull(dataSource); Assertions.assertNotNull(jdbc); } }
还要避免使用 @BeforeAll,因为它与静态内存相结合,而我们的 Bean 由 spring 管理,所以不能使用它,你可以用它代替你为 @BeforeEach 如果你想执行一些逻辑 你想要 运行 只对所有测试用例一次所以你可以做 hack 类似
private AtomicBoolean executed = new AtomicBoolean(false);
@BeforeEach
public void runOnce() {
if(!executed.getAndSet(true)) {
// write you logic which you want will run only once for all test cases
}
}