Why is Spring #Autowired ApplicationContext null in integration test? - java

I'm still new to Spring and have looked at similar questions on stack but couldn't identify an answer from what I've read.
I'm receiving an NPE when I call my applicationContext variable, which means the bean must not have been created or injected correctly. Here is the relevant portion of my program.
#SpringBootTest
#ContextConfiguration(classes = TestConfig.class)
public class SampleIT {
#Autowired
private ApplicationContext applicationContext;
#Test
public void sampleMethod() throws Exception {
//NPE below
String[] allBeanNames = applicationContext.getBeanDefinitionNames();
//more logic
I'm trying to get the ApplicationContext instance to debug why other beans are null from my config, so this all must be because of a basic flaw in my understanding of how ApplicationContext is setup and beans from it are injected. Any help is very much appreciated!

Try to add the following annotation to your class SampleIT:
#RunWith(SpringRunner.class)

Answering my own question now. Importing org.junit.jupiter.api.Test instead of org.junit.Test will cause Junit5 to be used. This will allow Junit to work with Spring without the #RunWith(SpringRunner.class) annotation. There are still remnants of Junit4 left in the codebase I'm working in, so this is a quick fix before completely moving to Junit 5.

If you are using Junit in version 4, You have to use #RunWith(SpringRunner.class),
If you are using Junit version 5, You have to use #ExtendWith(SpringExtension.class).
Additionally if you are using Mockito You can use #ExtendWith(MockitoExtension.class) etc.
I highly recommend read documentation about #SpringBootTest annotation in this link
#SpringBootTest

Related

Is new App() a good way to test if a spring boot app context loads?

I have just taken over maintenance of an app that has this as its only test: (Yes I know)
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#RequiredArgsConstructor
#SpringBootTest(classes = App.class)
#MockBean(ElasticSearchIndexService.class)
public class AppStartTest {
#Test
public void contextLoads() {
final var app = new App();
assertNotNull("the application context should have loaded.", app);
}
}
Apart from the fact that there is no automated testing in place is this a good way to test if a Spring boot application loads its context? I would have thought that a simple
assertTrue(true); in the test would suffice, as the context should be loaded no matter what. Why would I want to create another copy of the application? (I sadly could not find anything related to this during my google searches)
There is also the fact that it has both #RunWith(SpringRunner.class) and #SpringBootTest. The test currently "runs" properly but I would expect that this leads to some unexpected behaviour does it not? I found this SO answer talking about it but it does not go into depth why (or if ever) one should use both annotations.
Lastly I already removed the #RequiredArgsConstructor because I don't really know why it is there in the first place. In my humble opinion it does not really serve a purpose.
I am not certain if this fits SO but I was rather curious as I consider myself somewhat of a beginner Spring developer and maybe the previous dev knew more than me
is this a good way to test if a Spring boot application loads its context?
#M.Deinum already answered this
No it isn't. You should #Autowire your App or rather ApplicationContext and check that.
but for anyone looking for a code example it would look like this:
#Autowired
ApplicationContext applicationContext;
#Test
public void contextLoads() {
assertNotNull(applicationContext);
}
This checks if the Application Context was indeed initialized.
There is also the fact that it has both #RunWith(SpringRunner.class) and #SpringBootTest.
Is a remnant of this test initially using JUnit4, where this was indeed necessary. With JUnit5, which I am using the #RunWith(SpringRunner.class) can be left out.
I still am unsure why the #RequiredArgsConstructor annotation was ever needed but the test runs with and without it so I have removed it.

Trouble executing a unit test that should ignore Spring annotations on the unit under test

I'm trying to execute a unit test for a service class that has an #Async("asyncExecutor") annotated method. This is a plain JUnit test class with no Spring runners and no intention of using Spring at all in the unit test. I get the exception,
BeanFactory must be set on AnnotationAsyncExecutionAspect to access qualified executor 'asyncExecutor'
Where asyncExectuor is the name of the bean to be used during normal execution. My configuration class looks like this and I solved that previous error message at runtime by adding the mode = AdviceMode.ASPECTJ portion. This service works at runtime without issue in an Async way.
#Configuration
#EnableAsync(mode = AdviceMode.ASPECTJ)
public class AsyncConfiguration {
#Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
...
}
}
I don't understand why the Spring context is being constructed at all in the unit test. The test class is simply annotated #Test on the methods with no class annotations and no mention of Spring. I was hoping to unit test this service class method as a regular method ignoring the async nature, but the annotation is being processed for some reason.
I'm contributing to a much larger gradle + Spring 4 project that I'm not fully knowledgeable about. Is there anything I should be looking for to see if a Spring context is being created by default for all tests?
As you noticed, Spring context is not loaded, that is the reason of your error. Try to initialize Spring context in your test by adding #RunWith and #ContextConfiguration annotations

How to write integration/system test with Spring Boot to test service with repository

I have #Service in Spring Boot app which is parsing file and then storing it into DB using Spring Data JPA. I want to test this parsing with all logic of changing this mapping. So, for this I need to store mapping in DB in test.
#Service
public class ParsingService {
#Autowired
private StoringInDBRepository storingInDBRepository;
}
#Repository
public interface StoringInDBRepository extends JpaRepository<MyEntity, String> {
The problem is that during test with annotation #SpringBootTest I don't want to load the whole context, but only my ParsingService.
When I writing :
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {ParsingService.class})
public class ParsingServiceTest{
#Test
public void someTest(){
}
}
This test couldn't be initialized because I am not loading StoringInDBRepository in #SpringBootTest annotation. However I can do it, because StoringInDBRepository is an interface. Usage of #DataJpaTest according to javadoc will be correct only if I'm testing repository layer. Usage of #DataJpaTest and #SpringBootTest is not recommended.
How should I test such services?
Thanks in advance.
So, after all investigations I found a couple solutions. I chose to enable repositories and service with
#SpringBootTest(classes = {ParsingService.class})
#EnableJpaRepositories(basePackages = "com.my.repository")
#EntityScan("com.my.entity")
#AutoConfigureDataJpa
This is a workaround. And I don't think it is the best. The other solution is to create a #TestConfiguration which will return your service and all to use #DataJpaTest annotation to enable repository classes. In this case you should use #SpringBootTest annotation
You could use a #SpyBean to get what you want. It is fairly easy to use.
However - You don't actually need to test it in that way. Because by having your application context tested, you are making sure all classes get injected/autowired as they should be. Then separately test the method on the service level with mocks. And lastly, use #DataJpaTest to test it in the repository/DB level.
So you decouple your tests nicely: integration tests / unit tests / repository tests
There is no need to tightly couple all those three things in one class or test method.

Unable to use #DataJpaTest if Spring security is on classpath

I am trying to update my test cases to use the #DataJpaTest. However, I am encountering some issues that appear to be related to Spring Security. The following is an example of the test class.
#RunWith(SpringRunner.class)
#DataJpaTest
public class ExampleRepositoryTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
#Inject
private ExampleRepository repository;
#Test
public void test() throws Exception {
...
}
I keep getting the error java.lang.IllegalStateException: Failed to load ApplicationContext due to the missing bean org.springframework.security.config.annotation.ObjectPostProcessor.
The project is a RESTful application with Spring security. The original test case created a full Spring Boot context using #SpringBootTest. The #DataJpaTest is supposed to help me test the JPA slice, which is exactly what I want.
Any help would be greatly appreciated. What am I missing?
I got the same error.
for my case, I have added #SpringBootApplication and #EnableResourceServer on the same class.
when I move #EnableResourceServer to another configuration class, the error is gone.

spring junit testing

I have a maven spring project (latest version) and I want to write some junit tests (latest version).
The issue I have is that my spring beans are autowired, and when I call them from junit test, I get null pointer exceptions, as spring doesn't autowire them.
How can I load the context so that things are autowired?
Have you studied Testing chapter in Spring reference documentation? Here is an example you should start with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTest {
#Resource
private FooService fooService;
// class body...
}
If you are in com.example.MyTest in /src/test/java, you will need /src/test/resources/com/example/MyTest-context.xml - but the exceptions will show you the way.
This is a possibility:
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml"
// in the root of the classpath
#ContextConfiguration({"/applicationContext.xml"})
public class MyTest {
// class body...
}
Usually it's a good idea though to have a test-applicationContext for your test infrastructure.
You should use the SpringJUnit4ClassRunner on your test classes, and use #Resource (or #Autowired) on the field in your test class that contains the bean. You should consider having a special test context Spring configuration that uses stubs so that your tests are genuine unit tests, and don't rely on the whole application context.

Categories

Resources