Is it possible to override Spring bean in JUnit #Nested class? - spring

I can't find an elegant solution for overriding a property inside the Junit #Nested class.
What I wanted to achieve is to have something like the following:
#SpringBootTest
#NestedTestConfiguration(NestedTestConfiguration.EnclosingConfiguration.OVERRIDE)
class EnclosingClassTest {
#Test
void testA() {
...
}
#Nested
class NestedClassTest {
#TestConfiguration
static class InnerConfig {
#Bean
public ABean aBean() {
...
}
}
#Test
void testB() {
// Want use overridden ABean
...
}
}
}
Any help is much appreciated.

Related

How to inject certain properties values during junit to a specific test

My Spring Boot app has some test that are reading their properties from the application.yml that is in the test folder.
cat:
maxAge:30
maxNameSize:10
all is working fine, but I like that in certain tests, other values will be injected:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
Cat.class
})
#SpringBootTest
public class CatTest {
#Test
public void testX(){
//inject maxAge=90
// use maxNameSize from the application.yml
....
#Test
public void testZ(){
//inject maxNameSize=5
// use maxAge from the application.yml
....
}
Changing properties on method level is not supported by Spring at this moment.
You can use nested classes to accomplish this.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {
Cat.class
})
#SpringBootTest
public class CatTest {
#Nested
#SpringBootTest(properties = "cat.maxAge=90")
public class NestedTestX {
#Test
void testX() {
//noop
}
}
#Nested
#SpringBootTest(properties = "cat.maxNameSize=5")
public class NestedTestZ {
#Test
void testZ() {
//noop
}
}
}

Is there a way to get event in spring (+junit) fired after all tests classes?

I use spring 5 + junit 5. And I have two classes - BarIT and FooIT.
#ExtendWith({SpringExtension.class})
#ContextConfiguration(classes = ModuleContextConfig.class)
public class FooIT {
#Test
public void foo() {
System.out.println("Foo");
}
}
#ExtendWith({SpringExtension.class})
#ContextConfiguration(classes = ModuleContextConfig.class)
public class BarIT {
#Test
public void bar() {
System.out.println("Bar");
}
}
This is my suite:
#RunWith(JUnitPlatform.class)
#ExtendWith({SpringExtension.class})
#SelectClasses({
FooIT.class,
BarIT.class
})
#IncludeClassNamePatterns(".*IT$")
public class SuiteIT {
}
I want to get event when tests in two classes have been executed, I mean event after FooIT.foo() and BarIT.bar(), however, I can't do that. I hoped to get ContextClosedEvent but it is not fired:
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class ApplicationListenerBean implements ApplicationListener {
#Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("Event:" + event.toString());
}
}
And this is the output:
Event:org.springframework.context.event.ContextRefreshedEvent..
Event:org.springframework.test.context.event.PrepareTestInstanceEvent..
Event:org.springframework.test.context.event.BeforeTestMethodEvent..
Event:org.springframework.test.context.event.BeforeTestExecutionEvent..
Foo
Event:org.springframework.test.context.event.AfterTestExecutionEvent...
Event:org.springframework.test.context.event.AfterTestMethodEvent...
Event:org.springframework.test.context.event.AfterTestClassEvent...
Event:org.springframework.test.context.event.BeforeTestClassEvent...
Event:org.springframework.test.context.event.PrepareTestInstanceEvent...
Event:org.springframework.test.context.event.BeforeTestMethodEvent...
Event:org.springframework.test.context.event.BeforeTestExecutionEvent...
Bar
Event:org.springframework.test.context.event.AfterTestExecutionEvent...
Event:org.springframework.test.context.event.AfterTestMethodEvent...
Event:org.springframework.test.context.event.AfterTestClassEvent..
Could anyone say how to do it, if it is possible.

Reload Spring application using DirtiesContext annotation doesn't work with nested classes

I can't reload my spring application after each test into my nested classes:
/*...*/
#DirtiesContext( classMode = AFTER_EACH_TEST_METHOD )
public class MyTestClass {
#Nested
class MyNestedClass_1 {
#Test
void test_1() {
/*...*/
}
#Test
void test_2() {
/*...*/
}
}
#Nested
class MyNestedClass_2 {
/*..*/
}
}
Whereas, it works very well without nested class:
/*...*/
#DirtiesContext( classMode = AFTER_EACH_TEST_METHOD )
public class MyTestClass {
#Test
void test_1() {
/*...*/
}
#Test
void test_2() {
/*...*/
}
}
Does anybody have any idea why it doesn't work?
The Spring support for JUnit 5's #Nested class feature is currently limited. You can follow the progress to resolve this on GitHub. For the time being, I guess you have to remove the nested classes and follow the progress closely.
You can also find a possible workaround at this question by adding #DirtiesContext( classMode = AFTER_EACH_TEST_METHOD ) on top of your nested class:
#DirtiesContext( classMode = AFTER_EACH_TEST_METHOD )
public class MyTestClass {
#Nested
#SpringBootTest
#DirtiesContext( classMode = AFTER_EACH_TEST_METHOD )
class MyNestedClass_1 {
#Test
void test_1() {
/*...*/
}
#Test
void test_2() {
/*...*/
}
}
#Nested
#SpringBootTest
#DirtiesContext( classMode = AFTER_EACH_TEST_METHOD )
class MyNestedClass_2 {
/*..*/
}
}

Why did #TestConfiguration not create a bean for my test?

My service
#Service
public class StripeServiceImpl implements StripeService {
#Override
public int getCustomerId() {
return 2;
}
}
My test
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}
The error: java.lang.NullPointerException. I had checked and the stripeService is actually null.
Since you are autowiring you need an applicationcontext so that Spring can manage the bean and then can get injected in your class. Therefore you are missing an annotation to create the applicationcontext for your testclass.
I have updated your code and it works now(with junit 5 on your classpath). In the case dat you are using junit 4 it should be #RunWith(SpringRunner.class) instead of #ExtendWith(SpringExtension.class):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfiguration.class)
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}

Prevent method from running when using #EventListener(ApplicationReadyEvent.class) during testing

I have the following test class in my project
#RunWith(SpringRunner.class)
#SpringBootTest
public class AddressParserTest {
#Test
public void parseAddressTest() {
try {
// my code
} catch (IOException e) {
e.printStackTrace();
}
}
}
and I have some methods in my project that are annotated with #EventListener(ApplicationReadyEvent.class) which run after Spring Boot starts up
#Component
public class MyClass {
#EventListener(ApplicationReadyEvent.class)
public void myMethod() {
//my code
}
}
When I run the AddressParserTest the myMethod method also runs because of the #EventListener(ApplicationReadyEvent.class) is there anyway to prevent it from running during testing?
You could use profiles in this situation.
Annotate your class with #Profile (please note the "!" in front of "test". This means: load this class, only if the profile is not "test")
#Component
#Profile("!test")
public class MyClass {
#EventListener(ApplicationReadyEvent.class)
public void myMethod() {
//my code
}
}
Annotate your test class with #ActiveProfiles("test")
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
public class AddressParserTest {
#Test
public void parseAddressTest() {
try {
// my code
} catch (IOException e) {
e.printStackTrace();
}
}
}
Hope it helps !

Resources