I would like to write a unit test which is executed for every Spring bean of a given type. JUnit5's parameterized tests offer a lot of possibilities, but I don't know how to inject beans into a method source as it has to be a static method.
Is there a way to determine the parameters of a JUnit5 test based on Spring's application context?
For starters, a factory method configured via @MethodSource
does not have to be static
. The second sentence in the User Guide explains that.
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
.
Thus, if you use @TestInstance(PER_CLASS)
semantics, your @MethodSource
factory method can be non-static and can therefore access the ApplicationContext
injected into the test instance.
Here's an example that demonstrates that for beans of type String
, with an intentional failure for the 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";
}
}
}
If you don't want to work directly with the ApplicationContext
, you can simplify the solution by having the collection of all such beans of a given type (String
in this example) injected directly, as follows.
@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";
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With