#EnableAutoConfiguration on AbstractIntegrationTest possible? - spring-boot

Having lots of Integration-Test Implementations like this:
// no #Annotations at all
class SomeIntegrationTest extends AbstractIntegrationTest {
...
}
using (Spring Boot 1.5, JUnit 5)
#SpringBootTest(classes = {CoreConfiguration.class, RestTemplateAutoConfiguration.class, JacksonAutoConfiguration.class})
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
#Transactional
public abstract class AbstractIntegrationTest {
...
}
this is always failing with
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'javax.persistence.EntityManagerFactory' available
unless I annotate every IntegrationTest-Implementation with
#EnableAutoConfiguration
class SomeIntegrationTest extends AbstractIntegrationTest {
...
}
I wonder why I cannot #EnableAutoConfiguration the AbstractIntegrationTest and be done with it.
(When doing so, it fails with IllegalArgumentException: No auto-configuration attributes found. Is package.SomeIntegrationTest annotated with EnableAutoConfiguration?)
Our normal Apps look like this:
#SpringBootApplication
#Import({CoreConfiguration.class, OtherConfiguration.class})
public class WebApp {
here the #SpringBootApplication obviously implies #EnableAutoConfiguration but I would like to avoid annotating each and every *IntegrationTest with this and instead configure it once on the AbstractIntegrationTest.
Is this fighting against spring-boot in any way or is there some way to achieve this? Thanks.

You could create update your AbstractIntegrationTest abstract class to have a small inner configuration class e.g. TestConfiguration which is loaded using the #Import(TestConfiguration.class) annotation.
#SpringBootTest(classes = {CoreConfiguration.class, RestTemplateAutoConfiguration.class, JacksonAutoConfiguration.class})
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
#Transactional
#Import(AbstractIntegrationTest.TestConfiguration.class) // <---- import the configuration
public abstract class AbstractIntegrationTest {
#EnableAutoConfiguration
// Any other applicable annotations e.g. #EntityScan
static class TestConfiguration {
}
....
}

Related

Spring Junit and annotation based autowiring

I added a junit test to a simple spring example but it fails to autowire the json service that I wrote.
What is needed to get autowiring to work in a spring JUnit tests?
To try the failing project out do ...
git clone https://bitbucket.org/oakstair/spring-boot-cucumber-example
cd spring-boot-cucumber-example
./gradlew test
Thanks in advance!
Application
#SpringBootApplication
#ComponentScan("demo")
public class DemoApplication extends SpringBootServletInitializer {
Service interface
#Service
public interface JsonUtils {
<T> T fromJson(String json, Class<T> clazz);
String toJson(Object object);
}
Service implementation
#Component
public class JsonUtilsJacksonImpl implements JsonUtils {
Test
#ContextConfiguration()
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan("demo")
public class JsonUtilsTest {
#Autowired
private JsonUtils jsn;
In your JsonUtilsTest you can't put a #ComponentScan on the class level here since it isn't a #Configuration class. With a #ContextConfiguration annotation like you are using here it is first looking for a static inner #Configuration class so add one of those with the #ComponentScan and it should work:
#ContextConfiguration()
#RunWith(SpringJUnit4ClassRunner.class)
public class JsonUtilsTest {
#Autowired
private JsonUtils jsn;
#Test
// Note: This test is not tested since I haven't got autowiring to work.
public void fromJson() throws Exception {
Integer i = jsn.fromJson("12", Integer.class);
assertEquals(12, (int) i);
}
#Test
// Note: This test is not tested since I haven't got autowiring to work.
public void toJson() throws Exception {
assertEquals("12", jsn.toJson(new Integer(12)));
}
#Configuration
#ComponentScan("demo")
public static class TestConfiguration {
}
}
EDIT: Or you can make Spring boot do the work for you by using the #SpringBootTest annotation with a SpringRunner instead:
#RunWith(SpringRunner.class)
#SpringBootTest
public class JsonUtilsTest {
Adding this to the test class fixed my problems!
#ContextConfiguration(classes = {DemoApplication.class})
Add #SpringBootTest
On your test class
And provide your SpringBootApplication class and Json utils class to the classes field of #SpringBootTest
It should look like this
#ContextConfiguration()
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes={<package>.DemoApplication.class, <package>.JsonUtil.class } )
#ComponentScan("demo")
public class JsonUtilsTest {

How to override spring's import annotation

I have a spring boot application. In the main class annotated with #SpringBootApplication, I have imported some configurations, using the import annotation.
#SpringBootApplication
#Import({ MyConfiguration.class })
public class MySpringBootApp {
public static void main(String[] args) {
new SpringApplicationBuilder(MySpringBootApp.class).build().run(args);
}
}
Now when I run my junit test class, annotated with "#RunWith(SpringRunner.class)", it loads the application, and the imported configuartion classes in the main class, are also loaded (that is MyConfiguration).
#RunWith(SpringRunner.class)
public class MyTest {
....
}
Is there a way to override the import, so that MyConfiguration is not loaded while running tests.
I understand you need to use a SpringRunner but you want to use a different configuration. In that case you simply annotate your Test class with #ContextConfiguration(classes = SomeConfigurationClass.class)
So it would look like this:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = SomeConfigurationClass.class)
public class MyTest {
....
}
If you do not want any Spring Container, just remove #RunWith(...)

#ComponentScan takes no effect

I have the following code:
Implementation of Bean:
package my.persist.services;
#Component
public class MyService{
}
Test:
package my.persist.services;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={"other configuration classes", my.persist.services.MyService.class})
#ComponentScan(basePackageClasses = {my.persist.services.DummyPlaceHolder.class})
public class MyServiceTest extends AbstractJUnit4SpringContextTests {
#Autowired
MyService service;
}
When I remove "my.persist.services.MyService.class" from #ContextConfiguration, the compiler says "Could not autowire, no bean of ... found", it seems the #ComponentScan has no effect? Any help?
Rather than component scan for individual classes, does a wildcard scan of your base package work?
#ComponentScan(basePackages = {"my.persist.services.*"})
You can exclude certain ones in your test, i.e if you want to filter out your real implementation in your test, you can do the following:
#ComponentScan(basePackages = {"my.persist.services.*"}, excludeFilters={
#ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=MyService.class)})

Use #Primary to precede an #Component/#Service annotated class

In my project I have a service with the #Service annotation.
#Service
public class ExampleService { ... }
I would like to override this service with a Mockito-mock, using a configuration file for my test in the following way:
public class TestContext{
#Bean
#Primary
public ExampleService exampleService(){
return mock(ExampleService.class);
}
}
and in my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { WebContext.class, TestContext.class})
#WebAppConfiguration
public class TestExample{...}
For some reason the mocks aren't injected. The only way I can make this work is when I don't use #Service (#Component gives the same problem) but use a bean annotated method in the WebContext to load the ExampleService, and I put the TestClass behind the WebContext.class in the ContextConfiguration annotation (like in the code I wrote here). I don't get why, and I would like to know how I can keep using the #Service annotation.

DRY Spring AnnotationConfig testing

So, I'm working on some Spring tests which require dependency injection using annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class BeanTest {
#Autowired
private SomeService someService;
#Configuration
static class ContextConfiguration {
#Bean
public SomeService someService() {
return new SomeService();
}
}
}
I'd really like to not have to repeat this code in every test but my attempts to create a base class which contains the configuration:
#Configuration
class MyContextConfiguration {
#Bean
public SomeService someService() {
return new SomeService();
}
}
And deriving from it:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class BeanTest {
#Autowired
private SomeService someService;
#Configuration
static class ContextConfiguration extends MyContextConfiguration {}
}
Don't seem to work. Can anybody suggest a way to DRY this up?
Thanks!
You should be able to do this instead.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class BeanTest {
#Autowired
private SomeService someService;
#Configuration
#Import(MyContextConfiguration.class)
static class ContextConfiguration {
....
}
}
Also, you don't need to mention AnnotationConfigContextLoader, Spring by convention will automatically pick up the static inner class annotated with #Configuration and use the appropriate ContextLoader
You can declare configuration classes in the the contextconfiguration-annotation. From the documentation.
ContextConfiguration
Defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests. Specifically, #ContextConfiguration declares the application context resource locations or the annotated classes that will be used to load the context.
Resource locations are typically XML configuration files located in the classpath; whereas, annotated classes are typically #Configuration classes. However, resource locations can also refer to files in the file system, and annotated classes can be component classes, etc.
example from the documentation.
#ContextConfiguration(classes = TestConfig.class)
public class ConfigClassApplicationContextTests {
// class body...
}

Resources