I have the the following Spring Boot application (using Eureka and Feign):
#SpringBootApplication
#EnableFeignClients
#EnableRabbit
#EnableDiscoveryClient
#EnableTransactionManagement(proxyTargetClass = true)
public class EventServiceApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(EventServiceApplication.class, args);
}
}
and the following test, annotated with #SpringJpaTest:
#RunWith(SpringRunner.class)
#DataJpaTest(showSql = true)
public class EventRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private EventRepository repository;
#Test
public void testPersist() {
this.entityManager.persist(new PhoneCall());
List<Event> list = this.repository.findAll();
assertEquals(1, list.size());
}
}
While running the test I receive the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.netflix.discovery.EurekaClient] found for dependency [com.netflix.discovery.EurekaClient]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Full stacktrace here
Is there a way to solve this issue? I've seen that it is caused by #EnableFeignClients and #EnableDiscoveryClient annotations.
Finally I managed to solve my issue in the following way:
Added bootstrap.yml with the following contents:
eureka:
client:
enabled: false
spring:
cloud:
discovery:
enabled: false
config:
enabled: false
I written a test configuration and referenced it in the test:
#ContextConfiguration(classes = EventServiceApplicationTest.class)
where EventServiceApplicationTest is:
#SpringBootApplication
#EnableTransactionManagement(proxyTargetClass = true)
public class EventServiceApplicationTest {}
I don't know if there is an easiest way but this works.
I had similar problem with #EnableDiscoveryClient.
I think that in such cases the easiest approach is put disabling information:
eureka:
client:
enabled: false
in src/test/resources/application.[properties|yml]. Then during tests running this configuration has higher priority than src/main/resources/application.[properties|yml].
Since I assume you're only intending to test your repository layer, you could filter out the unneeded beans from your ApplicationContext related to Feign, etc.
You can configure an exclude filter via the excludeFilters attribute of #DataJpaTest.
Details on filters can be found in the Spring Reference Manual.
Another option would be to disable auto-configuration for Feign, etc. -- in which case you might find this answer useful: Disable security for unit tests with spring boot
The easiest way is to add the following configuration in your test class:
#RunWith(SpringRunner.class)
#TestPropertySource(properties={"eureka.client.enabled=false"})
#DataJpaTest(showSql = true)
public class BankRepositoryTest {
}
Related
I am doing a simple sample project with Spring boot and data.
#Configuration
public class MongoConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MongoConfig.class);
#Value("${mongo.uri}")
private String mongoUri;
public #Bean MongoClient mongoClient() {
LOGGER.info(" creating connection with mongodb with uri [{}] ", mongoUri);
return MongoClients.create(mongoUri);
}
}
This works fine and connects to mongo on startup. However, the tests also pick this up in autoscan. What is the best practice to make sure that mongo config gets excluded for tests?
If I add #WebMvcTest to the tests, it works. But not all tests will be mvc tests. I might be testing a utility class.
If I try using profiles, it gives my an error java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes: ...MongoConfig
#SpringBootTest
#ActiveProfiles("test")
class ApplicationTests {
#Test
void contextLoads() {
}
}
Please tell me a repeatable practice as I will be using it for all my tests.
The simplest way of doing it is to exclude your configuration bean when your test profile is active
#Profile("!test")
#Configuration
public class MongoConfig {
...
}
Here you tell to the BeanFactory to not create this bean if the profile test is present
Ref: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Profile.html
I have an application that use Elasticsearch and I'd like to disable this integration when I'm testing some controllers. How can I disable elasticsearchTemplate on Spring-Boot test?
Application.class:
#SpringBootApplication
#EnableElasticsearchRepositories(basePackages = "com.closeupinternational.comclosure.elasticsearch")
public class Application {
...
Repository.class:
#Repository
public interface PipelineRepository extends ElasticsearchRepository<Pipeline, String> {
...
Test Controller.class:
#ExtendWith(SpringExtension.class)
#EnableAutoConfiguration(exclude = {ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class})
#WebMvcTest(ProductionCycleExecutionController.class)
#Slf4j
public class ProductionCycleExecutionControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private ProductionCycleExecutionService prodCycleExecService;
...
I'm not using inside ProductionCycleExecutionService and I don't wanna try to test elasticsearch repository PipelineRepository at this moment.
Error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pipelineRepository' defined in
com.closeupinternational.comclosure.elasticsearch.PipelineRepository defined in
#EnableElasticsearchRepositories declared on Application: Cannot resolve reference to bean
'elasticsearchTemplate' while setting bean property 'elasticsearchOperations'; nested exception is org.springframework.beans.factory
Just remove #ExtendWith(SpringExtension.class) and #EnableAutoConfiguration(exclude = {ElasticsearchDataAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class})
These annotations aim to bootstrap the whole Spring context and configure it
#WebMvcTest should be enough in your case as it bootstraps web-related context only
Upd
If you have any dependencies in your ProductionCycleExecutionController (like elasticsearchTemplate you mentioned) then mock them like this if you don't need to define their behavior, as follows:
#MockBeans(value = {#MockBean(YourBean1.class), #MockBean(YourBean2.class), #MockBean(YourBean3.class)})
If you do need to define mocking behavior then mock as property in class:
#MockBean
private YourBean yourBean;
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;
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.
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