Not able to prevent couchbase autoconfiguration during tests - spring-boot

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;

Related

How to write #SpringBootTest for app with #ComponentScan and JPA repositories

I find it extremely hard to write #SpringBootTest if you use #ComponentScan and Jpa repositories. Can someone advice? This should be super-trivial stuff, but it's not documented anywhere.
#SpringBootApplication
#ComponentScan(
excludeFilters = {
#ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
#ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) },
basePackageClasses = {Main.class, Other.class})
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
and one of discovered Configuration classes has:
#Configuration
#EnableJpaRepositories("jpa")
Now I want to create test, which will enable ideally just a subset of JPA repositories AND exactly nothing else, unless I tell so. Namely, no configuration from production source code. This seems to be close to impossible to express. This is where I was able to get:
#RunWith(SpringRunner.class)
#SpringBootTest
#Import(TestIT.TestConfig.class)
public class TestIT {
#Configuration
#EnableJpaRepositories("jpa")
#AutoConfigureDataJpa
#AutoConfigurationPackage
public static class TestConfig {
//here will be beans for test.
}
so this configuration produces error
java.lang.IllegalArgumentException: Not a managed type ...my jpa repository class
which probably means, that jpa package isn't among autoconfigured packages. No idea how to add it if it's even possible.
OK, another approach. Some sources recommends this:
#RunWith(SpringRunner.class)
#SpringBootTest
#Import(TestIT.TestConfig.class)
public class TestIT {
EnableJpaRepositories("jpa")
#EntityScan(basePackages = "jpa.entities")
//#TestPropertySource("classpath:application.properties")
#EnableTransactionManagement
public static class TestConfig {
//here will be beans for test.
}
but this one fails with caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
Any hints?
First of all, there is no specific need to add #ComponentScan in your main application startup file. #SpringBootApplication is sufficient.
Now regarding the test cases:
I use powermockito all my test cases usually look like this:-
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#PrepareForTest({ ContextProvider.class, ConfigurationUtils.class, Utils.class })
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestIT {
IN the clause #PrepareForTest mention all the classes which u would mention with the annotation #Mock.
for e.g.
No need to mention any of the repo(DAO layer interfaces where we write our queries) interfaces. So ur repo declaration would be like:
private SoftwareRepo softwareRepo;
And u would use it in while execution is
softwareInventoryRepo = PowerMockito.mock(SoftwareRepo.class);
OK, after a lot of searching (in vain) and even more trying, I think I have answer.
To recap:
you have main class (thanks #Bhushan Shinde):
#SpringBootApplication(scanBasePackageClasses = {Main.class, Other.class})
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
and some configuration:
#Configuration
#EnableJpaRepositories("jpa")
public class Config
So to use SpringBootTest and configure everything from scratch for test, ignoring production configurations, you go:
#RunWith(SpringRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.NONE,
classes = TestIT.TestConfig.class)
//#Import(TestIT.TestConfig.class)
public class TestIT {
#Configuration
#AutoConfigureDataJpa
#EnableJpaRepositories("jpa") //fake package names, obviously
#EntityScan(basePackages = "jpa.entities")
// #TestPropertySource("classpath:application.properties")
#EnableTransactionManagement
public static class TestConfig {
//test related beans & config.
}
//tests here.
}
maybe there is something extra here, but after day of googling & trying this is good enough for me.

Spring boot how to exclude certain class from testing

I have implemented own class for representing of database vector data based on UserType class.
My example:
class MyVectorType implements UserType {
#Override
public int[] sqlTypes() {
return new int[] { Types.ARRAY };
}
};
#Entity
#Table("MY_ENTITY")
public class MyEntity {
private MyVectorType myVectorType;
}
However this class cannot be used in testing with h2 dialect ie. in memory database. There is error: No Dialect mapping for JDBC type: 2003.
Therefore I would like to exclude this entity (inc. repository) from testing but this does not work:
#SpringBootApplication
#ComponentScan(excludeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {
MyEntity.class, MyEntityRepository.class})
})
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
What is wrong or is there any best practice solving this problem?
EDIT 1: fixed examples - added correct entity and repository
SOLUTION 1:
I think that the only possible solution for this moment is move entity classes (which needs to be excluded) to other package. Then set #EntityScan to scan just non-excluded package. Exclude filters in ComponentScan seems to work only in case of #Component classes, not #Entity. However this is not absolutely best practice to solve this problem.
Just define it as a #MockBean so the real implementation of your repository will be replaced by a functionless mock in your tests:
#MockBean
private MyVectorRepositoryType vectorRepository;
I had a similar problem and I excluded the application configuration in my test configuration, as it seems the test config component scans the application config component scans the classes you want to exclude.

Error while exluding MongoDataAutoConfiguration

I've tried to exclude mongoDB autoconfiguration from a spring-boot project but i keep having that error:
Method mvcConversionService in org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport required a bean named 'mongoTemplate' that could not be found.
Configuration:
#SpringBootApplication
#EnableAutoConfiguration(exclude = {MongoDataAutoConfiguration.class})
public class ChromeDataCoreApplication {
public static void main(String[] args) {
SpringApplication.run(ChromeDataCoreApplication.class, args);
}
}
Any help?
Thanks.
I found that in my case I had an interface that was annotated with #Repository and even though nothing depended on it Spring Boot created it anyway and tried to connect to the Mongo database.
WebMvcConfigurerComposite#addFormatters tries to add HateoasAwareSpringDataWebConfiguration which, in turn, requires the mongoTemplate bean. To fix this I was able to put an annotation on my repository interface:
#ConditionalOnProperty(name = "mongo.enabled", havingValue = "true")
To remove the HateoasAwareSpringWebConfiguration bean from the list of delegates used in addFormatters the following can be added to your #SpringBootApplication:
#SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration.class})
Of course I also included the two classes for Mongo auto configuration:
#SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, SpringDataWebAutoConfiguration.class})
I should note that once the #ConditionalOnProperty annotation was added to the repository interface the SpringDataWebAutoConfiguration.class was no longer required.

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

using ConfigFileApplicationContextInitializer does not resolve default values for #Value

When I am using:
#ContextConfiguration(classes = { DmiVehicleRTExportConfig.class },
initializers = ConfigFileApplicationContextInitializer.class)
my integration tests are failing as properties such as:
${oauth2client.prematureTimeout:600}
are not getting default value of 600.
This is resolved through using: SpringApplicationConfiguration but I want to use ConfigFileApplicationContextInitializer.class instead of SpringApplicationConfiguration.
Thanks.
I had the same issue. PropertySourcesPlaceholderConfigurer.class needs to be added:
#ContextConfiguration(classes = { DmiVehicleRTExportConfig.class,
PropertySourcesPlaceholderConfigurer.class },
initializers = ConfigFileApplicationContextInitializer.class)
Spring team has just added a note about that:
Using ConfigFileApplicationContextInitializer alone won’t provide support for #Value("${…​}") injection. Its only job is to ensure that application.properties files are loaded into Spring’s Environment. For #Value support you need to either additionally configure a PropertySourcesPlaceholderConfigurer or use #SpringBootTest where one will be auto-configured for you.
I had this problem in JUnit tests also when using
#SpringApplicationConfiguration
I solve this by adding a class with a 'static void main()' method to the configuration classes :
#Configuration
public class SpringEmptyApplication{
public static void main(String[] args) {
SpringApplication.run(SpringBootEmptyApplication.class);
}
}
I put this class as first to the list of configuration classes like
#SpringApplicationConfiguration(classes = {
SpringBootEmptyApplication.class,
DmiVehicleRTExportConfig.class
})
This works perfect for me.
If you want to avoid
#SpringApplicationConfiguration
you can try
#ContextConfiguration(loader = SpringApplicationContextLoader.class ...
This is how #SpringApplicationConfiguration itself is annotated, may be this loader can fix the problem, did not try...

Resources