How to exclude classes that are added using Spring's AutoConfiguration when using #WebMvcTest? - spring

I want to test my Controller using #WebMvcTest and mock the dependencies, but Spring Boot's AutoConfiguration loads my Couchbase (Spring Data) configuration automatically. Couchbase is not available on some platforms which run the test, so the Test class will throw an Exception. How can I exclude some classes from the AutoConfiguration mechanism?
I tried the excludeFilters option of #WebMvcTest and #ActiveProfile to load another Application Context, but that didn't work.
Test configuration:
#RunWith(SpringRunner.class)
#WebMvcTest(value = ExchangeJobImportController.class, excludeFilters = #ComponentScan.Filter(classes = CouchbaseConfiguration.class))
#ActiveProfiles("test")
public class ExchangeJobImportControllerTest {
...
}
Couchbase Configuration:
#Configuration
#EnableCouchbaseAuditing
#EnableConfigurationProperties({CouchbaseProperties.class})
#EnableCouchbaseRepositories(basePackages = "com....")
public class CouchbaseConfiguration extends AbstractCouchbaseConfiguration {
...
}

After some more struggling I found the solution: exclude the #SpringBootApplication annotated class in the #WebMvcTest annotation:
#RunWith(SpringRunner.class)
#WebMvcTest(value = ExchangeJobImportController.class, excludeAutoConfiguration = Application.class, secure = false)
#ActiveProfiles("localhost")
public class ExchangeJobImportControllerTest {
...
}
For the record, I am using Spring Boot 1.5.1.RELEASE

I know it's been some time but I suppose the reason why the #ComponentScan.Filter solution doesn't work is that it looks for an annotation type for the classes field by default.
So, setting the FilterType as ASSIGNABLE_TYPE should work in your case:
#ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = CouchbaseConfiguration.class
)

Related

How to disable #Configuration initialization in WebFluxTest?

I would like to write tests for reactive controller using #WebFluxTest annotation, mocking all dependencies.
#WebFluxTest(controllers = MyController.class)
public class MyControllerTest {
#MockBean
SomeService service;
#Autowired
WebTestClient webClient;
//some tests
}
From what I understand, the WebFluxTest annotation shall apply only configuration relevant to WebFlux tests (i.e. #Controller, #ControllerAdvice, etc.), but not another beans.
My spring boot app contains a number of #Configuration classes that configure a number of beans (annotated as #Bean). Some of those configurations have also dependencies (autowired by constructor).
#Configuration
#RequiredArgsConstructor
public class MyConfig {
private final AnotherConfig anotherConfig;
#Bean
//...
}
When I run my web flux tests, I can see the context initialization contains an attempt to initialize the MyConfig (and it fails because of the missing dependency which comes from 3rd party auto-configured lib). How can I configure the test to skip initialization of all of these?
I am able to exclude the problematic configuration class only by excluding auto configuration of the whole app.
#WebFluxTest(controllers = MyController.class, excludeAutoConfiguration = {MyApplication.class})
public class MyControllerTest { ... }
where MyApplication is the spring boot app autoscanning those configuration classes.
But how can I achieve to skip initialization of MyConfig only? Or even better, how can I achieve to only include a list of configurations to be initialized?
Add
#ActiveProfiles("YOUR_ENV_OTHER_THAN_TEST")
below or above #Configuration
For multiple environments..
#ActiveProfiles(profiles ={env1, env2,env3})

Not able to prevent couchbase autoconfiguration during tests

I am trying to prevent the application from attempting to connect to the DB while running the Unit tests. Following is what I have done.
#SpringBootApplication(exclude = {
CouchbaseDataAutoConfiguration.class,
CouchbaseAutoConfiguration.class,
})
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ApplicationStartup.class, MessageApplication.class }))
public class MessageApplicationTests {
public static void main(String[] args) {
SpringApplication.run(MessageApplicationTests.class, args);
}
}
#ActiveProfiles("test")
#SpringBootTest(classes = MessageApplicationTests.class)
class TestClass {
#Autowired
Serviceclass serviceclass;
#Test
void testMethod() {
}
}
Apart from this, I have added the following in application-test.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration
- org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration
- org.springframework.cloud.aws.autoconfigure.messaging.MessagingAutoConfiguration
Both are not helping.
Can someone help me understand what is wrong here?
Also exclude your Config class (the one that extends AbstractCouchbaseConfig)
But if you have any references to repositories such as via Autowire or as args to #Service constructors, the application will fail to start. The exclude of auto configuration classes did not seem to matter when I tried it.
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ApplicationStartup.class, MessageApplication.class, Config.class}))
Probably not related to your issue, but I found that with multiple #SpringBootApplication classes (you have MessageApplication and MessageApplicationTests, right?), that Spring goes through the auto-config classes for both of them, not just the one in
SpringApplication.run(MessageApplicationTests.class, args) ) So one would need #SpringBootApplication excludes on both classes to completely exclude them (although I found that excluding didn't change anything).
The spring-data-couchbase project tests provide a mock couchbase server (src/test/resources/integration.properties -> mocked) or can use a standalone couchbase server (unmanaged). That might be useful for your testing.
The above answer posted by Michael Reiche is correct. Adding few more points to address the concern raised by him.
We need to exclude the configuration class for Couchbase. But the autowired repository beans would create a problem then.
To resolve it we can mock the repository beans so that it doesn't try to create actual repository beans and load them to the context.
Not including the autoconfiguration classes in the exclusion list did matter for me, as it would try to configure the Couchbase since the dependency is there in the classpath
#SpringBootApplication(exclude = {
CouchbaseDataAutoConfiguration.class, CouchbaseAutoConfiguration.class,
CouchbaseRepositoriesAutoConfiguration.class, CouchbaseReactiveDataAutoConfiguration.class,
CouchbaseReactiveHealthContributorAutoConfiguration.class
})
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ApplicationStartup.class, MessageApplication.class , CouchBaseConfiguration.class }))
public class MessageApplicationTests {
#MockBean
Repositoryclass repoBean;

How to exclude classes with #Configuration in #SpringBootApplication testing

I am using a dependent module called spring-cloud-aws. It has a #Configuration class as org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration
In my SpringBoot JUnit test case the SqsConfiguration class is getting detected and Beans are getting initialized. I want to exclude this Configuration in class in my JUNit test case. How to achieve this ?
I tried using #ComponentScan it didn't work.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = SQLTestConfig.class)
#ActiveProfiles("test")
public class BusinessManagerTest {
}
#TestConfiguration
#ComponentScan(basePackages = {"package1","package1"},
excludeFilters = {#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = SqsConfiguration.class)})
#Profile("test")
class SQLTestConfig {
#Bean
public SomeBean beans() {
return new SomeBean();
}
}
Loading this configuration class requires aws credentials to be available. I don't want to inject credentials for running a simple Bean test case.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleMessageListenerContainer' defined in class path resource [org/springframework/cloud/aws/messaging/config/annotation/SqsConfiguration.class]: Invocation of init method failed; nested exception is com.amazonaws.services.sqs.model.AmazonSQSException: The security token included in the request is expired
There are multiple ways to exclude specific auto-configuration during testing:
exclude via properties in your application-test.properties
spring.autoconfigure.exclude=org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration
exclude via #TestPropertySource:
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
#SpringBootTest(classes = SQLTestConfig.class)
#TestPropertySource(properties ="spring.autoconfigure.exclude=org.springframework.cloud.aws.messaging.config.annotation.SqsConfiguration")
exclude via #EnableAutoConfiguration, e.g.:
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
#SpringBootTest(classes = SQLTestConfig.class)
#EnableAutoConfiguration(exclude=SqsConfiguration.class)
Choose one that suites you better ;)
So to disable the auto-loading of all Beans for a Test, the test class can explicitly mention the dependencies required. This can be done using ContextConfiguration annotation. eg,
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {EmployeeService.class})
public class EmployeeLeavesTest {
#Autowired
private EmployeeService employeeService;
}
In this eg, only EmployeeService class will be available and other beans will not be loaded.

Spring boot cucumber testing

I try to perform some Cucumber tests of a Spring boot application.
It seems like Spring Boot is not started before tests are running.
What am i missing?
https://bitbucket.org/oakstair/spring-boot-cucumber-example
My Cucumber repo still runs without doing all the above steps:
https://github.com/BarathArivazhagan/Cucumber-spring-integration
Docs : https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
To add more:
#SpringBootTest takes care of loading the application context in that case #ContextConfiguration is reductant.
Spring test automatically provides a bean of TestRestTemplate which can be autowired but still it should work with RestTemplate also.
It still runs without RANDOM_PORT but RANDOM port can be also used in conjunction for testing.
Let's say you have a feature file, feature1, and glueCode in org.xyz.feature1
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty"},
features = "src/test/java/resources/feature/feature1",
glue = {"org.xyz.feature1"})
public class CucumberTest {
}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {Application.class},
webEnvironment = WebEnvironment.RANDOM_PORT)
#ContextConfiguration
#Ignore
#Transactional
public class FeatureTest extends CucumberTest {
#LocalServerPort
int randomServerPort;
#Given("........")
public void test_1 {
}
}
I found the problem and has updated the repo.
I did the following to get it working:
Added RANDOM_PORT to #SpringBootTest
Added #ContextConfiguration
Switched from RestTemplate to TestRestTemplate

How to exclude/disable a specific auto-configuration in Spring boot 1.4.0 for #DataJpaTest?

I am using the #DataJpaTest from Spring for my test which will then use H2 as in memory database as described here . I'm also using Flyway for production. However once the test starts FLyway kicks in and reads the SQL file. How can I exclude the FlywayAutoConfiguration and keep the rest as described here in spring documentation in order to let Hibernate create the tables in H2 for me?
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private MyRepository triggerRepository;
}
Have you tried the #OverrideAutoConfiguration annotation?
It says it "can be used to override #EnableAutoConfiguration".
I'm assuming that from there you can somehow exclude FlywayAutoConfiguration
like so:
#EnableAutoConfiguration(exclude=FlywayAutoConfiguration.class)
Adding the dependency on an in-memory database to my build.gradle
e.g. testRuntime "com.h2database:h2:1.4.194"
And adding flyway.enabled=false to application.properties in src/test/resources worked for me.
I am converting an old JDBC app into a spring-data-jpa app and I'm working on the first tests now. I kept seeing a security module instantiation error from spring-boot as it tried to bootstrap the security setup, even though #DataJpaTest should theoretically be excluding it.
My problem with the security module probably stems from the pre-existing implementation which I inherited using PropertySourcesPlaceholderConfigurer (via my PropertySpringConfig import below)
Following the docs here:
http://docs.spring.io/spring-boot/docs/1.4.x/reference/htmlsingle/#test-auto-configuration
and your comments on #LiviaMorunianu's answer, I managed to work my way past every spring-boot exception and get JUnit to run with an auto-configured embedded DB.
My main/production spring-boot bootstrap class bootstraps everything including the stuff I want to exclude from my tests. So instead of using #DataJpaTest, I copied much of what it is doing, using #Import to bring in the centralized configurations that every test / live setup will use.
I also had issues because of the package structure I use, since initially I was running the test which was based in com.mycompany.repositories and it didn't find the entities in com.mycompany.entities.
Below are the relevant classes.
JUnit Test
#RunWith(SpringRunner.class)
#Transactional
#Import({TestConfiguration.class, LiveConfiguration.class})
public class ForecastRepositoryTests {
#Autowired
ForecastRepository repository;
Forecast forecast;
#Before
public void setUp() {
forecast = createDummyForecast(TEST_NAME, 12345L);
}
#Test
public void testFindSavedForecastById() {
forecast = repository.save(forecast);
assertThat(repository.findOne(forecast.getId()), is(forecast));
}
Live Configuration
#Configuration
#EnableJpaRepositories(basePackages = {"com.mycompany.repository"})
#EntityScan(basePackages = {"com.mycompany.entity"})
#Import({PropertySpringConfig.class})
public class LiveConfiguration {}
Test Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestConfiguration {
// lots of bean definitions...
}
PropertySpringConfig
#Configuration
public class PropertySpringConfig {
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
throws IOException {
return new CorePropertySourcesPlaceholderConfigurer(
System.getProperties());
}
}
In my particular case, i needed to disable the FlywayDB on in-memory integration tests. These are using a set of spring annotations for auto-configuring a limited applicationContext.
#ImportAutoConfiguration(value = TestConfig.class, exclude = FlywayAutoConfiguration.class)
the exclude could effectively further limit the set of beans initiated for this test
I had the same problem with my DbUnit tests defined in Spock test classes. In my case I was able to disable the Flyway migration and managed to initialize the H2 test database tables like this:
#SpringBootTest(classes = MyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = ["flyway.enabled=false", "spring.datasource.schema=db/migration/h2/V1__init.sql"])
I added this annotation to my Spock test specification class. Also, I was only able to make it work if I also added the context configuration annotation:
#ContextConfiguration(classes = MyApplication.class)
I resolved the same issue by excluding the autoconfiguration from my application definition, i.e.
#SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
you can also sue the following annotation:
#RunWith(SpringRunner.class)
#DataJpaTest(excludeAutoConfiguration = {MySqlConfiguration.class, ...})
public class TheClassYouAreUnitTesting {
}
You can just disable it in your test yaml file:
flyway.enabled: false

Resources