如何在静态@BeforeClass 中自动装配字段?
How to autowire field in static @BeforeClass?
@RunWith(SpringJUnit4ClassRunner.class)
public void ITest {
@Autowired
private EntityRepository dao;
@BeforeClass
public static void init() {
dao.save(initialEntity); //not possible as field is not static
}
}
如何在静态初始化中注入我的服务 class?
要回答这个问题,我们应该回顾一下 Spring 2.x 个版本。
如果你想 "autowire" 你的 @BeforeTest
中的一个 bean class 你可以使用 ApplicationContext
接口。让我们看一个例子:
@BeforeClass
public static void init() {
ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
EntityRepository dao2 = (EntityRepository) context.getBean("dao");
List<EntityRepository> all = dao2.getAll();
Assert.assertNotNull(all);
}
发生了什么:使用 ClassPathXmlApplicationContext
我们正在实例化 application-context.xml
文件中包含的所有 beans。
使用 context.getBean()
我们读取指定的 bean(它必须匹配 bean 的名称!);然后你可以用它来进行初始化。
您应该给 bean 另一个名称(即 dao2
!)否则 Spring 正常 "autowired" 无法在预定义的 bean 上工作。
附带说明一下,如果您的测试扩展了 AbstractTransactionalJUnit4SpringContextTests
,您可以使用 executeSqlScript(sqlResourcePath, continueOnError)
进行一些初始化;方法,因此您不依赖于还必须单独测试的 class/method。
在我看来,您正试图在测试前填充数据库。
我会尝试两种选择:
- 如果您可以将初始脚本提取到 sql 文件(如果您可以选择不使用存储库 bean),则可以使用 this approach 并使用
@Sql
[= 注释您的测试30=]
- 您可以探索 DbUnit and here is link to spring dbunit connector which is doing exactly that and helping you populate DB before tests. Here is a github link 在 spring 测试框架和 dbunit 之间进行集成。在你这样做之后你有
@DatabaseSetup
和 @DatabaseTearDown
这将在你需要的数据库上做事
我知道这并没有回答如何在静态中注入 bean @BeforeClass
但是形成代码看起来它正在解决你的问题。
更新:
我最近 运行 在我的项目中遇到了同样的问题并挖掘出 this article 这对我有帮助,我认为这是处理此类问题的优雅方式。您可以使用侦听器扩展 SpringJUnit4ClassRunner
,侦听器可以使用您定义的所有 bean 进行实例级设置。
我一直在使用的一种解决方法是使用 @Before
和一个标志来跳过它正在为每个测试用例执行
@RunWith(SpringJUnit4ClassRunner.class)
public class BaseTest {
@Autowired
private Service1 service1;
@Autowired
private Service2 service2;
private static boolean dataLoaded = false;
@Before
public void setUp() throws Exception {
if (!dataLoaded) {
service1.something();
service2.somethingElse();
dataLoaded = true;
}
}
}
Spring 2.x 版本更新。
Spring 2.x 支持 Junit 5 Jupiter 的新功能 SpringExtension
,您只需:
用@ExtendWith(SpringExtension.class)
声明你的测试class
用 bean
注入您的 @BeforeAll
(JUnit 5 中 @BeforeClass
的替代品)
例如:
@ExtendWith(SpringExtension.class)
...
public void ITest {
@BeforeAll
public static void init(@Autowired EntityRepository dao) {
dao.save(initialEntity);
}
}
假设您使用 Spring 2.x
正确配置了 JUnit 5 Jupiter
使用 Junit 5 你可以做到这一点(@BeforeAll 而不是 @BeforeClass)
public void ITest {
@Autowired
private EntityRepository dao;
@BeforeAll
public static void init(@Autowired EntityRepository dao) {
dao.save(initialEntity); //possible now as autowired function parameter is used
}
}
离开该字段意味着它可以用于其他测试
如果您只想在测试中使用一些数据库数据,您还可以模拟存储库并使用 Narain Mittal 描述的解决方法:
@RunWith(SpringJUnit4ClassRunner.class)
public void ITest {
@MockBean
private EntityRepository dao;
@Before
public static void init() {
when(dao.save(any())).thenReturn(initialEntity);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
public void ITest {
@Autowired
private EntityRepository dao;
@BeforeClass
public static void init() {
dao.save(initialEntity); //not possible as field is not static
}
}
如何在静态初始化中注入我的服务 class?
要回答这个问题,我们应该回顾一下 Spring 2.x 个版本。
如果你想 "autowire" 你的 @BeforeTest
中的一个 bean class 你可以使用 ApplicationContext
接口。让我们看一个例子:
@BeforeClass
public static void init() {
ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
EntityRepository dao2 = (EntityRepository) context.getBean("dao");
List<EntityRepository> all = dao2.getAll();
Assert.assertNotNull(all);
}
发生了什么:使用 ClassPathXmlApplicationContext
我们正在实例化 application-context.xml
文件中包含的所有 beans。
使用 context.getBean()
我们读取指定的 bean(它必须匹配 bean 的名称!);然后你可以用它来进行初始化。
您应该给 bean 另一个名称(即 dao2
!)否则 Spring 正常 "autowired" 无法在预定义的 bean 上工作。
附带说明一下,如果您的测试扩展了 AbstractTransactionalJUnit4SpringContextTests
,您可以使用 executeSqlScript(sqlResourcePath, continueOnError)
进行一些初始化;方法,因此您不依赖于还必须单独测试的 class/method。
在我看来,您正试图在测试前填充数据库。
我会尝试两种选择:
- 如果您可以将初始脚本提取到 sql 文件(如果您可以选择不使用存储库 bean),则可以使用 this approach 并使用
@Sql
[= 注释您的测试30=] - 您可以探索 DbUnit and here is link to spring dbunit connector which is doing exactly that and helping you populate DB before tests. Here is a github link 在 spring 测试框架和 dbunit 之间进行集成。在你这样做之后你有
@DatabaseSetup
和@DatabaseTearDown
这将在你需要的数据库上做事
我知道这并没有回答如何在静态中注入 bean @BeforeClass
但是形成代码看起来它正在解决你的问题。
更新:
我最近 运行 在我的项目中遇到了同样的问题并挖掘出 this article 这对我有帮助,我认为这是处理此类问题的优雅方式。您可以使用侦听器扩展 SpringJUnit4ClassRunner
,侦听器可以使用您定义的所有 bean 进行实例级设置。
我一直在使用的一种解决方法是使用 @Before
和一个标志来跳过它正在为每个测试用例执行
@RunWith(SpringJUnit4ClassRunner.class)
public class BaseTest {
@Autowired
private Service1 service1;
@Autowired
private Service2 service2;
private static boolean dataLoaded = false;
@Before
public void setUp() throws Exception {
if (!dataLoaded) {
service1.something();
service2.somethingElse();
dataLoaded = true;
}
}
}
Spring 2.x 版本更新。
Spring 2.x 支持 Junit 5 Jupiter 的新功能 SpringExtension
,您只需:
用
@ExtendWith(SpringExtension.class)
声明你的测试class
用 bean
注入您的
@BeforeAll
(JUnit 5 中 @BeforeClass
的替代品)
例如:
@ExtendWith(SpringExtension.class)
...
public void ITest {
@BeforeAll
public static void init(@Autowired EntityRepository dao) {
dao.save(initialEntity);
}
}
假设您使用 Spring 2.x
正确配置了 JUnit 5 Jupiter使用 Junit 5 你可以做到这一点(@BeforeAll 而不是 @BeforeClass)
public void ITest {
@Autowired
private EntityRepository dao;
@BeforeAll
public static void init(@Autowired EntityRepository dao) {
dao.save(initialEntity); //possible now as autowired function parameter is used
}
}
离开该字段意味着它可以用于其他测试
如果您只想在测试中使用一些数据库数据,您还可以模拟存储库并使用
@RunWith(SpringJUnit4ClassRunner.class)
public void ITest {
@MockBean
private EntityRepository dao;
@Before
public static void init() {
when(dao.save(any())).thenReturn(initialEntity);
}
}