是否可以使用 Spring ApplicationContext 中的 bean 参数化 JUnit Jupiter 测试?
Is it possible to parameterize a JUnit Jupiter test with beans from a Spring ApplicationContext?
我想编写一个单元测试,为给定类型的每个 Spring bean 执行。 JUnit5 的参数化测试提供了很多可能性,但我不知道如何将 bean 注入到方法源中,因为它必须是静态方法。
有没有办法根据 Spring 的应用程序上下文确定 JUnit5 测试的参数?
对于初学者来说,通过 @MethodSource
配置的工厂方法不一定是 static
。 User Guide 中的第二句解释了这一点。
Factory methods within the test class must be static
unless the test class is annotated with @TestInstance(Lifecycle.PER_CLASS)
; whereas, factory methods in external classes must always be static
.
因此,如果您使用 @TestInstance(PER_CLASS)
语义,您的 @MethodSource
工厂方法可以是 non-static,因此可以访问注入到测试实例中的 ApplicationContext
。
这是一个示例,它演示了 String
类型的 bean,bar
bean 有意失败。
import java.util.stream.Stream;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests {
@Autowired
ApplicationContext applicationContext;
@ParameterizedTest
@MethodSource
void stringBeans(String bean) {
assertEquals(3, bean.length());
}
Stream<String> stringBeans() {
return applicationContext.getBeansOfType(String.class).values().stream();
}
@Configuration
static class Config {
@Bean
String foo() {
return "foo";
}
@Bean
String bar() {
return "barf";
}
}
}
如果您不想直接使用 ApplicationContext
,您可以通过注入给定类型的所有此类 bean(本例中为 String
)的集合来简化解决方案直接如下。
@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests {
@Autowired
List<String> stringBeans;
@ParameterizedTest
@MethodSource
void stringBeans(String bean) {
assertEquals(3, bean.length());
}
Stream<String> stringBeans() {
return this.stringBeans.stream();
}
@Configuration
static class Config {
@Bean
String foo() {
return "foo";
}
@Bean
String bar() {
return "barf";
}
}
}
使用 @TestFactory
可能会有所帮助。
实际上,我偶然发现了一个 post,它与您在 github 上做的事情非常相似(或相同)。
让您的测试 运行 与 SpringExtenion
并使用注入的 Bean 作为我们测试的参数。
我想编写一个单元测试,为给定类型的每个 Spring bean 执行。 JUnit5 的参数化测试提供了很多可能性,但我不知道如何将 bean 注入到方法源中,因为它必须是静态方法。
有没有办法根据 Spring 的应用程序上下文确定 JUnit5 测试的参数?
对于初学者来说,通过 @MethodSource
配置的工厂方法不一定是 static
。 User Guide 中的第二句解释了这一点。
Factory methods within the test class must be
static
unless the test class is annotated with@TestInstance(Lifecycle.PER_CLASS)
; whereas, factory methods in external classes must always bestatic
.
因此,如果您使用 @TestInstance(PER_CLASS)
语义,您的 @MethodSource
工厂方法可以是 non-static,因此可以访问注入到测试实例中的 ApplicationContext
。
这是一个示例,它演示了 String
类型的 bean,bar
bean 有意失败。
import java.util.stream.Stream;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests {
@Autowired
ApplicationContext applicationContext;
@ParameterizedTest
@MethodSource
void stringBeans(String bean) {
assertEquals(3, bean.length());
}
Stream<String> stringBeans() {
return applicationContext.getBeansOfType(String.class).values().stream();
}
@Configuration
static class Config {
@Bean
String foo() {
return "foo";
}
@Bean
String bar() {
return "barf";
}
}
}
如果您不想直接使用 ApplicationContext
,您可以通过注入给定类型的所有此类 bean(本例中为 String
)的集合来简化解决方案直接如下。
@SpringJUnitConfig
@TestInstance(PER_CLASS)
class SpringBeansParameterizedTests {
@Autowired
List<String> stringBeans;
@ParameterizedTest
@MethodSource
void stringBeans(String bean) {
assertEquals(3, bean.length());
}
Stream<String> stringBeans() {
return this.stringBeans.stream();
}
@Configuration
static class Config {
@Bean
String foo() {
return "foo";
}
@Bean
String bar() {
return "barf";
}
}
}
使用 @TestFactory
可能会有所帮助。
实际上,我偶然发现了一个 post,它与您在 github 上做的事情非常相似(或相同)。
让您的测试 运行 与 SpringExtenion
并使用注入的 Bean 作为我们测试的参数。