I have been using #Configuration support in Spring to create my Mockito Mocks for use in JUnit tests
#Configuration
public class MockAppContextHelper {
#Bean
public IntegrationServerServiceWrapper integrationServerServiceWrapperTest() {
return mock(IntegrationServerServiceWrapper.class);
}
}
This used to work fine in Spring 3.0.2.
In Spring 3.1 I get the following error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'integrationServerServiceWrapperTest' defined in class path resource [com/kn/bpa/task/service/impl/MockAppContextHelper.class]: No matching factory method found: factory bean 'mockAppContextHelper'; factory method 'integrationServerServiceWrapperTest()'. Check that a method with the specified name exists and that it is non-static.
Any ideas?
Thanks for your support
Consider adding a reproduction project per the instructions at https://github.com/SpringSource/spring-framework-issues#readme that demonstrates the configuration in question working in 3.0.2 and failing against 3.1.x
Related
The context is I am using s3mock-junit5 for mocking s3 using groovy's Spock framework
testImplementation group: 'com.adobe.testing', name: 's3mock-junit5', version: '2.4.10'
I had to write a groovy's custom Extension because s3mock does work with junit4 and 5 out of the box but not with Spock.
package com.myapp.test.utils
...
class S3MockTestExtension extends S3MockStarter implements IAnnotationDrivenExtension<S3MockTest> {
Eventually the s3mock library runs a spring boot app (to mock the s3 behavior)
final ConfigurableApplicationContext ctx =
new SpringApplicationBuilder(S3MockApplication.class)
.properties(translateLegacyProperties(defaults))
.properties(translateLegacyProperties(properties))
.bannerMode(bannerMode)
.run(args);
The problem I have is that it tries to create beans that my app uses (the data source and amazon's SdkClient):
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception; nested exception is org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
at app//org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at app//org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
... 97 more
Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException: Failed to determine a suitable driver class
Why does it do that? The library spring boot Application class has a #ComponentScan annotation, but the base package is way different from my app's package.
package com.adobe.testing.s3mock;
...
#Configuration
#EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class},
excludeName = {"org.springframework.boot.actuate.autoconfigure.security.servlet."
+ "ManagementWebSecurityAutoConfiguration"})
#ComponentScan
public class S3MockApplication {
I tried to upgrade my data-mongo example project to Spring Boot 2.6.0. There is a test designed to run against Testcontainers, I also included the embedded mongo dep for other tests, so I have to exclude the AutoConfiguration for embedded mongo to make sure this test working on Docker/testcontainers.
The following configuration worked well with Spring Boot 2.5.6.
#DataMongoTest
#ContextConfiguration(initializers = {MongodbContainerInitializer.class})
#EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
#Slf4j
#ActiveProfiles("test")
public class PostRepositoryTest {}
But after upgrading to Spring Boot 2.6.0 and running the application, I got the exception like this.
[ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: o
rg.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'embeddedMongoServer' defined in class path resource [org/springframework/boot/autoconfig
ure/mongo/embedded/EmbeddedMongoAutoConfiguration.class]: Unsatisfied dependency expressed through method 'embeddedMongoServer' parameter 0; nested exception is org.springframework.bea
ns.factory.BeanCreationException: Error creating bean with name 'embeddedMongoConfiguration' defined in class path resource [org/springframework/boot/autoconfigure/mongo/embedded/Embed
dedMongoAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.flap
doodle.embed.mongo.config.MongodConfig]: Factory method 'embeddedMongoConfiguration' threw exception; nested exception is java.lang.IllegalStateException: Set the spring.mongodb.embedd
ed.version property or define your own MongodConfig bean to use embedded MongoDB
Obviously, #EnableAutoConfiguration(exclude =...) did not affect the context in tests when upgrading to Spring Boot 2.6.0.
Update: Temporarily resolved it, see my answer below.
Just add:
#TestPropertySource(properties = "spring.mongodb.embedded.version=3.5.5")
annotation before your Unit Test and it will start working.
#Henning's answer has a good explanation of why you need this.
As of Spring Boot 2.6, the property spring.mongodb.embedded.version must be set to use the auto-configured embedded MongoDB. It's mentioned in the release notes: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#embedded-mongo
This is also what the error message you posted, advises to do: Set the spring.mongodb.embedd ed.version property or define your own MongodConfig bean to use embedded MongoDB
The annotation #DataMongoTest is meta-annotated with #ImportAutoConfiguration and #AutoConfigureDataMongo, and is designed to trigger auto-configuration of MongoDB unless explicitly disabled as you do in the working configuration examples.
In your first configuration example, the annotation #EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class) does not override this effect of #DataMongoTest.
With Spring Boot 2.5.6, the auto-configured MongodConfig bean is most likely also part of the application context but not effectively used. But this depends on the rest of the code and in particular on the MongodbContainerInitializer.
Use #ImportAutoConfiguration(exclude = ...) or #DataMongoTest(excludeAutoConfiguration = ...) on test classes to overcome this barrier when upgrading to Spring Boot 2.6.0.
#DataMongoTest
#ImportAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
//other config are ommitted
public class PostRepositoryTest {}
//or
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class PostRepositoryTest {}
I found another post on Stackoverflow that was similar to my question. But It was saying "don't use Camel case in #ConfigurationProperties".
But, I'm not using Camel case. So that's why asking a new question.
I'm using below code in Spring Boot 2.1:
#Configuration
#EnableConfigurationProperties(UMAAppProperties.class)
public class UMAAppConfig {
}
and
#ConfigurationProperties("app") //all properties are within the 'app' hierarchy
public class UMAAppProperties {
}
In application.yml, I'm writing:
app: // This single line only. Nothing after that for app:
But, I'm getting below exception:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'UMAAppConfig': Unsatisfied dependency expressed through field
'umaAppProperties';
nested exception is org.springframework.boot.context.properties.ConfigurationPropertiesBindException:
Error creating bean with name 'app-com.common.finding.abc.configuration.UMAAppProperties': Could not
bind properties to 'UMAAppProperties' : prefix=app, ignoreInvalidFields=false,
ignoreUnknownFields=true;
Any solution for that??
I found the answer:
As there is nothing under app: in application.yml , then means we have to comment this line.
I have a service, a bean, that contains a #Transactional method:
public class InMessageService {
...
#Transactional
public boolean retryInMessage(String messageId) {
...
}
}
For testing, I try to mock that service with Mockito:
#Bean
#Primary
public InMessageService inMessageService() {
return Mockito.mock(InMessageService.class);
}
The result of this is the following exception when I start the test:
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB
subclass of class somePackage.InMessageService$MockitoMock$156222813: Common
causes of this problem include using a final class or a non-visible class;nested exception is
org.springframework.cglib.core.CodeGenerationException: java.lang.NoClassDefFoundError-->
somePath/InMessageService$MockitoMock$156222813
I want to mention that the same code was working with spring-boot 1.2.1 and Mockito 1.10.19. I try to run the above code with spring boot 2.1.1 and Mockito 2.23.0
My observations so far:
No matter what Mockito version between 2.1.0 and 2.23.0 I use, the exception is the same. I cannot (and don't want to) use older versions of Mockito as the project does not compile any more
If I temporary remove the #Transactional annotation, the exception is not thrown.
Any ideas what has to be adjusted with the upgrade of spring boot so the tests work again ?
Thank you !
Since version 2.1.0 Mockito retains annotations on proxied methods. This means that Spring attempts to proxy the mock class that declares a transactional annotation and this fails, because the mocking method is final.
Before, Mockito stripped these annotations what would have caused any real method call to fail due to the missing transaction.
To avoid this, you would need to strip the annotations of the mock. You can do so using MockSettings.withoutAnnotations.
The error is thrown while trying to unit test the Service class that contains an autowired Dao object which internally uses an Autowired JdbcTemplate in Spring boot Rest service using Junit and Mockito
in you `SpringBootTest you should pass config classes or properties files where all configs are.
Probably dataSource is missing
#SpringBootTest(classes = YouAppRunnerOrConfig.class, properties = "...")