Error creating bean with name 'flywayInitializer' with flyway-test-extension - spring-boot

So I have two integration test classes. I am using the flyway-test-extension for resetting the db. When I run the test classes individually from IntelliJ, both pass. However, when I run them with mvn clean install or in IntelliJ all test together, TestClass2 fails with an exception.
Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.api.FlywayException: Found non-empty schema(s) "public" without schema history table! Use baseline() or set baselineOnMigrate to true to initialize the schema history table.
I tried setting spring.flyway.baseline-on-migrate=true in the core_test.proberties file, but without success.
Difference between TestClass1 and TestClass2 is that #FlywayTest is once on class level and once on method level. Also in TestClass1 I use #MockBean for some of my services. Might this cause the error?
These are the tests I have:
#SpringBootTest(classes = { CoreTestConfig.class })
#TestPropertySource("classpath:core_test.properties")
#ExtendWith(SpringExtension.class)
#ExtendWith({FlywayTestExtension.class})
#FlywayTest // on class level
class TestClass1 {
// contains injected mocks #MockBean
}
#SpringBootTest(classes = { CoreTestConfig.class })
#TestPropertySource("classpath:core_test.properties")
#ExtendWith(SpringExtension.class)
#ExtendWith({FlywayTestExtension.class})
class TestClass2 {
#Test
#FlywayTest // on method level
void someTestMethod() {
// ...
}
}
and the context configuration for the test as follows:
#Configuration
#EnableAutoConfiguration
#EnableConfigurationProperties({
AppProperties.class
})
#EnableTransactionManagement
#EnableAsync
#EnableScheduling
#Import({ActivitiConfiguration.class})
#ComponentScan(basePackages = { "com.company.product.core" },
excludeFilters = #ComponentScan.Filter(value = Configuration.class)
)
#EntityScan(basePackageClasses = BaseDO.class)
#EnableJpaRepositories(basePackages = "com.company.product.core.repository")
public class CoreTestConfig {
// contains some specific test beans
}
I use org.flywaydb.flyway-test-extensions version 6.4.0.
UPDATE: When I remove #MockBean inside TestClass1, there are no more errors when running all tests together. But how am I supposed to use #MockBean with the flyway test extension?

As shown in this tutorial, mocking the beans inside of the CoreTestConfig class resolved the issue. I am not sure why but it works. And then simply #Autowire for the mocked services inside the tests.

Related

IntelliJ Idea + Could not autowire. No beans of type found

I keep seeing below error in my IntelliJ Idea, however the code works fine during execution.
Could not autowire. No beans of 'PortfolioRequestHandler' type found. less... (Ctrl+F1)
Inspection info:Checks autowiring problems in a bean class.
Sample Code
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
#SpringBootTest(classes = {Application.class})
public class PortfolioRequestHandlerTest {
#Autowired
private PortfolioRequestHandler portfolioRequestHandler;
...
...
}
How do I get rid of this? I am using IntelliJ Idea ULTIMATE 2018.2
Are you sure that your Spring beans are wired correctly and that it's an IDE problem?
check if your PortfolioRequestHandler class is annotated with #Service, #Component or #Repository (bean config via component scanning)
otherwise check if your bean is wired in a #Configuration annotated class -> in that case there should be a method that returns an instance of type PortfolioRequestHandler and that's annotated with #Bean
try adding a configuration class (as mentioned in 2.) and add this class to your #SpringBootTest(classes = {...} annotation; see example below
#Configuration
public class CustomBeanConfig {
#Bean
public PortfolioRequestHandler get PortfolioRequestHandler() {
return new PortfolioRequestHandler();
}
}
#SpringBootTest(classes = {Application.class, CustomBeanConfig.class})
have a look at this one, maybe helps: https://stackoverflow.com/a/50267869/150623

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.

How to load mongo repository to spring test application context?

I have to implement some test for some spring application. I am using #SpringBootTest annotation in my test:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest(){
//some tests...
}
It works fine, but i do not want to load all application context and and limit it by adding one or more nessecary configuration class. I done it with #ContextHierarchy:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#ContextHierarchy(ContextConfiguration(classes = [SomeCofigClass1::class, SomeConfigClass2::class]))
class MyTest(){
//some tests...
}
//for example
class SomeCofigClass1(){
#Bean
fun(someMongoRepository: SomeMongoRepository){ \\<-- Problem is here
return SomeService(someMongoRepository)
}
}
/**
* My repository.
*/
interface SomeMongoRepository : MongoRepository<Job, String> {}
Because of context is partially loaded i got a error:
No qualifying bean of type 'SomeMongoRepository' available:....
How can i load repository in test application context?
I already tried:
1) Added #AutoConfigureDataMongo. I got error java.lang.IllegalStateException: Unable to retrieve #EnableAutoConfiguration base packages
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#ContextHierarchy(ContextConfiguration(classes = [SomeCofigClass1::class, SomeConfigClass2::class]))
#AutoConfigureDataMongo
2) Replaced #SpringBootTest by #DataMongoTest. I got error Unable to retrieve #EnableAutoConfiguration base packages
#DataMongoTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#ContextHierarchy(ContextConfiguration(classes = [SomeCofigClass1::class, SomeConfigClass2::class]))
3) With #DataMongoTest replaced #ContextHierarchy by #Import. With #Import annotation it loads all application context. This is not suit for me.
#DataMongoTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#Import(SomeCofigClass1::class, SomeConfigClass2::class)
Add #RunWith(SpringRunner.class) to load Spring's ApplicationContext during the test.
Furthermore, classes can be selected by using the #SpringBootTest#classes attribute (or #ContextConfiguration):
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {SomeCofigClass1.class, SomeConfigClass2.class})
If your test makes use of inner Configuration classes, be sure to make them static (and add #Configuration). From the documentation:
If you omit the classes attribute from the #ContextConfiguration annotation, the TestContext framework tries to detect the presence of
default configuration classes. Specifically,
AnnotationConfigContextLoader and AnnotationConfigWebContextLoader
detect all static nested classes of the test class that meet the
requirements for configuration class implementations, as specified in
the #Configuration javadoc.

Modify the bean created in main application context during Integration test

In my springboot application I am performing Integration tests using the following class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = AccountLoadApplication.class,
loader = SpringApplicationContextLoader.class)
#WebIntegrationTest(randomPort = true)
public class LoaderTest {
AccountLoadApplication.class is a spring boot main class and the actual application has a bean defined like below:
#Bean
public ResourceLoader recapMvsFileResourceLoader() {
return new RemoteFileResourceLoader(remoteHostProperties(), new SFTPRemoteFileService());
}
Also I have a Test Configuration class like below
#Configuration
public class AtddTestConfig {
#Bean
public ResourceLoader mvsFileResourceLoader() {
ResourceLoader recapMvsFileResourceLoader =
new RemoteFileResourceLoader(remoteHostProperties(), new FakeSFTPRemoteFileService());
return recapMvsFileResourceLoader;
}
My Idea is that I want to override the bean created in the main application using the new bean defined in the test Configuration file.
But during integration tests the main application bean is considered instead of the bean defined in the test application context?
Is There any other way to achieve what i am trying to achieve ?
Additional Info:
Here are the beans defined in my Application configuration class
#Bean
public RemoteFileService remoteFileService() {
return new SFTPRemoteFileService();
}
#Bean
public ResourceLoader recapMvsFileResourceLoader() {
return new RemoteFileResourceLoader(remoteHostProperties(), remoteFileService());
}
Here are the beans defined in my Test configuration class
#Bean
#Profile("local")
#Primary
public RemoteFileService remoteFileService() {
return new FakeSFTPRemoteFileService();
}
Still the production bean is only created instead of this primary bean.
Use #Profile annotation to enable testing bean only in test context
Use #Primary annotation on testing bean, so that spring would use test bean instead of production one.
Here is my Github repository with working example using this mechanism.
Maybe when you add your test configuration as parameter for #ContextConfiguration it resolves problem, e.g.
#ContextConfiguration(classes = {AccountLoadApplication.class, AtddTestConfig.class},
loader = SpringApplicationContextLoader.class)
Along with the other changes suggested by #luboskrnac, you have to declare #ActiveProfiles; otherwise, your local profile is simply ignored.
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("local")
#SpringApplicationConfiguration(AccountLoadApplication.class)
#WebIntegrationTest(randomPort = true)
public class LoaderTest { /* ... */ }
Note that the above assumes that your AtddTestConfig class gets picked up via component scanning by your AccountLoadApplication class.

Spring junit error single matching bean but found 2

I have a test class, and have created a java config class to use with this class.. But im having issues as other tests seem to throw up found two instances of bean in configuration...
my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=TestConfiguration.class)
public class ListenerTest {
// various tests.. just basic stuff..
}
#Configuration
public class TestConfiguration {
#Bean
public MyListsner ListenerImpl() {
return Mockito.mock(MyListsner .class);
}
}
Now for this test class passes fine when i use a mock as above. My other test classes seem to fail and they are as follows:
test class which fails...
This class throws the error
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=GeneratorTestConfiguration.class)
#Transactional
public class GeneratorTest {
// various tests
}
Main config
#Configuration
#Import({
BaseConfiguration.class,
CoreBaseConfiguration.class
})
#Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
#EnableTransactionManagement(proxyTargetClass = true)
#EnableJpaRepositories(basePackages={
"com.persistence.repository"
})
#ComponentScan({ // where the components are
"com.tests"
})
public class GeneratorTestConfiguration {
}
I dont know why, when i add listener mock to the above class ListenerTest, the toher tests fail, as im being specific in those classes to use the relevant configuration when autowiring.
Seems the bean was defined twice.

Resources