Exclude ApplicationStartup Event listener when testing - java

I recently added an ApplicationStartup class to my SpringBoot project
#Component
public class ApplicationStartup
implements ApplicationListener<ApplicationReadyEvent> { ...
It implements ApplicationListener.
Now when I run my old JUNit tests that have nothing to do with that class, The testrunner tries to Run my StartupListener, which is neither necessary not appropriate in these cases.
How do I skip the ApplicationListener when my tests initialize?
#RunWith(SpringRunner.class)
#SpringBootTest
public class SubmissionItemManagerTest {...

You can mock your ApplicationStartup class
Add this declaration to your test case:
#MockBean
private ApplicationStartup applicationStartup
This will create a mocked instance of ApplicationStartup and mark it as #Primary in your test context thereby replacing the actual instance ofApplicationStartup.

You can create a separate application class for testing and exclude the components that are not required for tests:
#SpringBootApplication
#ComponentScan(excludeFilters = #ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
value = { ApplicationStartup.class,
RealApplication.class }))
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
}
Then in your SubmissionItemManagerTest class use the TestApplication class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = TestApplication.class)
public class SubmissionItemManagerTest {
...
}

Related

SpringJUnitConfig for mulitple junit classes

In our project, every Junit class(which is annotated using SpringJunitConfig) is having a #Configuration annotated class, which creates the Bean which is required to test any particular Test-class method.
Example:
#SpringJunitConfig
class TestClass {
#Configuration
class TestConfig {
#Bean
public TestClass testClass(DependantBean dependantBean) {
return new TestClass(dependantBean);
}
#Bean
public DependantBean dependantBean() {
return new DependantBean();
}
}
#Autowire private TestClass testClass;
#Test
void testMethod() {
//do testing
}
}
However this looks handy for a single test class, but the issue is every test class is having its own configuration class, which we are trying to avoid and I wanted to have one single configuration class for my whole test classes. Can someone help me to remove this repeated #Configuration?
Thanks in advance.
You could easily create a Configuration meant only for Test cases, and it could be used in #SpringJunitConfig:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/junit/jupiter/SpringJUnitConfig.html
#SpringJUnitConfig is a composed annotation that combines
#ExtendWith(SpringExtension.class) from JUnit Jupiter with
#ContextConfiguration from the Spring TestContext Framework.
Define your TestConfig:
#Configuration
public class ValidationTestSpringConfig {
#Bean
public TaskScheduler validationTaskScheduler() {
ThreadPoolTaskScheduler tpts = new ThreadPoolTaskScheduler();
tpts.setPoolSize(2);
return tpts;
}
}
Then using this #SpringJunitConfig annotation, you can actually provide the context configuration you need, which loads up the Test Beans:
#SpringJUnitConfig(ValidationTestSpringConfig.class)
public class HttpValidationIntegrationTest {
#Autowired
private TaskScheduler taskScheduler;
}

null service when testing with MockitoJUnitRunner

I have this test in my Spring Boot app., but when I run the test, boniUserService is null
#RunWith(MockitoJUnitRunner.class)
public class BoniUserServiceTest {
private BoniUserService boniUserService;
#Test
public void getUserById() {
boniUserService.getUserById("ss");
}
}
The runner of your test that you specify with #RunWith annotation specify who is going to process the annotation in your test class. They process the annotation in your test class and mock objects for you. In your case you have annotated your class with #RunWith(MockitoJUnitRunner.class) So there should be some annotation of Mockito in your class to be processed by MockitoJUnitRunner. To achieve your goal you can annotate your bean by #MockBean annotation.
#RunWith(MockitoJUnitRunner.class)
public class BoniUserServiceTest {
#MockBean
private BoniUserService boniUserService;
#Test
public void getUserById() {
boniUserService.getUserById("ss");
}
}
Note that in this approach the Context of the Spring Application is not loaded. Usually you want to test one of your component based on mocked behavior of other components. So usually you achieve that like this:
#RunWith(SpringRunner.class)
#SpringBootTest
public class BoniUserServiceTest {
#Autowired
private BoniUserService boniUserService;
#MockBean
private BoniUserRepository boniUserRepository;
#Test
public void getUserById() {
given(this.boniUserRepository.getUserFromRepository()).willReturn(new BoinoUsr("test"));
boniUserService.getUserById("ss");
}
}
You need to have the application context up to make it work, it can be achieved by using the #SpringBootTest annotation, and then you need to inject your service using the #Autowired annotation. Something like this:
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class BoniUserServiceTest {
#Autowired
private BoniUserService boniUserService;
#Test
public void getUserById() {
boniUserService.getUserById("ss");
}
}

How to autowire beans in test class when using #SpringBootTest

I have an integration test class annotated with #SpringBootTest which starts up the full application context and lets me execute my tests. However I am unable to #Autowired beans into the test class itself. Instead I get an error:
No qualifying bean of type 'my.package.MyHelper' available".
If I do not #Autowire my helper class, but keep the code directly inside the setUp function, the test works as expected.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
public class CacheControlTest {
#Autowired
private MyHelper myHelper;
#Before
public void setUp() {
myHelper.doSomeStuff();
}
#Test
public void test1() {
// My test
}
}
How can I make use of Spring autowiring inside the test class while also using #SpringBootTest?
Following #user7294900 advice below, creating a separate #Configuration file and adding this at the top of CacheControlTest works:
#ContextConfiguration(classes = { CacheControlTestConfiguration.class })
However is there any way of keeping the configuration inside the CacheControlTest class itself? I have tried adding inside my test class:
public class CacheControlTest {
#TestConfiguration
static class CacheControlTestConfiguration {
#Bean
public MyHelper myHelper() {
return new MyHelper();
}
}
}
And
public class CacheControlTest {
#Configuration
static class CacheControlTestConfiguration {
#Bean
public MyHelper myHelper() {
return new MyHelper();
}
}
}
But they do not seem to have any effect. I still get the same error. The same configuration block works when placed in an separate file as mentioned above though.
Add ContextConfiguration for your Test Class:
#ContextConfiguration(classes = { CacheControlTestConfiguration.class })

Unit testing with SpringJUnit4ClassRunner using only #Component and #Autowired

I have the following class:
#Component
public class MyClass {
#Autowired MyPojo pojo;
}
How do i test it without mocking the injected beans? I do not have a configuration [XML or declarative].
I have done the following:
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan
public class MyClassTest {
#Autowired MyClass myClass;
#Test
public void test() {
this.myClass...()
}
}
If you do not want use any type of configuration, neither Java nor XML config, you can use #ContextConfiguration with your component classes listed:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { MyPojo.class, MyClass.class })
public class MyClassTest {
#Autowired
private MyClass myClass;
#Test
public void test() {
// myClass...
}
}
Please note that MyPojo class should also be annotated with #Component.
However, in the real life scenario you probably will need at least one #Configuration class (which can be also used with #ContextConfiguration).
Please refer Spring Documentation for more information about Spring integration tests support.

Junit 5 test, getting java.lang.IllegalStateException: Test classes cannot include #Bean methods

#ContextConfiguration(classes = ConfigureCustomConfigurationModelProviderTest.class)
public class ConfigureCustomConfigurationModelProviderTest extends AbstractContextTest {
#Bean(name = "smth")
public static ConfigurationModelProvider get() {
return AnnotationConfigurationModelProvider.getInstance();
}
/*...*/
}
I'm getting this error since migrating from junit4 to junit5. Why?
You should move every beans to #Configuration class for example TestConfig:
#Configuration
public class TestConfig {
#Bean(name = "smth")
public static ConfigurationModelProvider get() {
return AnnotationConfigurationModelProvider.getInstance();
}
}
and import it via #Import:
#Import({TestConfig.class})
#ContextConfiguration(classes = ConfigureCustomConfigurationModelProviderTest.class)
public class ConfigureCustomConfigurationModelProviderTest extends AbstractContextTest {
}
To add to Amir's answer: if you only need the bean for some tests you can omit the #Configuration annotation at the top.

Categories