Issue
I created a Spring Boot Java library which has a set of utilities that perform certain functions. This library can then be used across multiple applications that require its utilities. This library was designed as a Spring Boot application to allow these utilities to be injected in the application context.
Now I wish to execute a JUnit test on one of the utilities to ensure it is working correctly. However, since this application is basically a collection of utilities and not a stand-alone application, it does not have a main class or the main method annotated with @SpringBootApplication
. Now, when I run the JUnit test, it comes up with an error.
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...)
Is it possible to test this Java library, or should we write the test cases only in the application that will be using this library?
Solution
I think there is some contradiction in what you say:
- Created a Library...that was designed as a Spring Boot Application.
- Library can be used across multiple applications that require its utilities.
If you implement "1" then there is a module with spring boot maven/gradle plugin configured to create a JAR of the application which is a library.
But if you have, say, module X that wishes to use your library, its impossible to add the dependency on your library in this module, spring boot JAR artifacts are not JARs in a Java Sense... So this won't work in both IDE and maven (I mean technically you'll have compilation errors).
Then you write something that completely makes sense: You say that the library by itself doesn't have a main class/@SpringBootApplication
annotated class. From this I conclude that its not a spring boot application, but rather a spring boot starter module.
In this case you should not use @SpringBootTest
annotation since it mimics the way of starting up the spring boot application (finds main class, scans the packages according to the package structure, loads the configurations and so forth). You don't need all this. Well, maybe technically you can still create a main class annotated with @SpringBootApplication
and put it into src/test/java/.../
in a relevant package, but it doesn't really makes sense.
So basically you have two choices:
You can test the utilities without spring at all as if the utility is just a Java class, mock the dependency with Mockito and you're good to go. Since these tests are fast, it you be the best option.
You can run the integartion test by means of loading the spring context with all the required beans created by the application.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {MyLibraryConfiguration.class})
public class SampleLibraryTest {
@Autowired
private SomeBeanFromTheLibrary theBean;
@Test
public void testFoo() {
....
}
}
Now although you can use component scanning (in this case you'll need slightly different annotations), in the example I've assumed that you're using java config, register all the beans of the library there and create a spring.factories
that uses this Java Configuration file to create an autoconfiguration (you add a dependency on the library in module X and it loads the beans defined in the library automatically).
This @ExtendsWith
(@RunWith
for junit 4) has nothing to do with Spring Boot, it behaves as a "plain" spring, you can autowire beans, create mock beans, there is caching of configurations, etc.
Answered By - Mark Bramnik
Answer Checked By - Robin (JavaFixing Admin)