How to disable kafka connection from spring boot test? - spring-boot

I am using spring kafka to consume message from kafka topic, so I have a kafka consumer configuration class:
#Configuration
class KafkaConfiguration {
// kafka consumer configurations
}
I have some JUnit tests which will load spring context with mockMvc to test my API, I don't want to test features related to kafka messaging, how can I stop kafka from consuming message only for JUnit tests? It keep failing because I don't have a kafka server at my local and CI environment.
Spring profile is not a very good option, because I will have to write code like:
#Configuration
#Profile("!unit-test")
class KafkaConfiguration {
//kafka configuration
}
which I will end up with production code written only for testing purpose, not very clean, is there other way I can do to disable kafka for tests?

Add #ConditionalOnProperty annotation on configuration class
Example:
#ConditionalOnProperty(value = "kafka.enable", havingValue = "true", matchIfMissing = true)
, and add application.properties file property kafka.enable=false

Spring Profiles have exactly this purpose. It always enabling/disabling parts of your application for various scenario's under which your application runs (staging, production, unit tests).
The only other option would be to make Kafka available during the test by using TestContainers for example.

Related

Mix spring-integration and spring scheduler

We are mixing spring-integration and the scheduling capabilities from spring-boot using:
#SpringBootApplication
#EnableIntegration
#IntegrationComponentScan
#EnableConfigurationProperties
#EnableScheduling
public class MyApplication {
...
}
#EnableScheduling creates a bean named "taskScheduler" which is then used by spring-integration:
public abstract class IntegrationContextUtils {
public static final String TASK_SCHEDULER_BEAN_NAME = "taskScheduler";
...
}
private void registerTaskScheduler() {
if (!this.beanFactory.containsBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME)) {
...
this.registry.registerBeanDefinition(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, scheduler);
}
}
Problem is, the default poolSize for spring-integration is 10 (which value is needed as we encounter starvation) while the default for spring-boot is 1 (which we also need to avoid concurrency in our scheduled processes).
Questions:
Is this a normal behavior for spring-integration to share his task scheduler bean with spring-boot scheduling capabilities?
Is there a way to specify a unique task scheduler for spring-integration, whether scheduling in boot is enabled or not?
Thanks for your answers
The behviour and logic is correct. And expectations from the convention-on-configuration from Spring Boot perspective is also correct. Only what you miss that #EnableScheduling is not a Spring Boot feature, but rather Spring Framework native: https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#scheduling. Spring Boot jsut give us an extra freedom of configuration some beans on the matter. So, we just need to rely on its auto-configuration.
If auto-configuration doesn't fit your requirements, you always can provide your own configuration and override whenever it is necessary.
Looking to the #EnableScheduling, its #Scheduled hooks and appropriate TaskSchedulingAutoConfiguration in Spring Boot, it is not so easy to override whatever you want to make Spring Integration happy at the same time. So, we should go a bit opposite direction and really override a Scheduler for Spring Integration endpoints. Every single place where you use poller, you also need to configure a custom Scheduler instead of that auto-configured.

#JmsListener not calling from Integration Test

I have integrated ActiveMQ with my Spring-Boot application and it's working fine. But When I'm trying to create Integration test for my #JmsListener with Embedded ActiveMQ it's only looking for external ActiveMQ not internal.
So my Case always failed. Is there anyway to override default application.yml with application-test.yml so my Receiver call which have #JmsListner look for embedded-broker url not external one (which I have declared in application.yml)
To override, use #TestPropertySource
Example:
#TestPropertySource(locations = "classpath:application-test.yml")
public class IntegrationClass {
Your application-test.yml should be placed in src/test/resources/

Disable autoconfiguration for Spring Cloud Config in a test class of a Spring Boot application

I have a test class annotated with #DataJpaTest which autoconfigures Cloud Config.
I want to stop that for that one test class. I cannot use the spring.cloud.config.enabled=false application property, because that would disable it for all tests.
Any suggestions?
#DataJpaTest annotation has other attributes. I tried the following to specifically disable the Spring Cloud Config and it worked for me locally:
#DataJpaTest(properties = {"spring.cloud.config.enabled=false"})
#DataJpaTest takes a excludeAutoConfiguration argument. You can specify all the AutoConfig's which you want to exclude.
#DataJpaTest(excludeAutoConfiguration = {AbcCloudAutoConfig.class, DefCloudAutoConfig.class})
replace AbcCloudAutoConfig, DefCloudAutoConfig with the classes you want to exclude

Spring cloud stream kafka binder to create consumer with on demand configuration

I am using Spring boot 1.5.9.RELEASE and Spring cloud Edgware.RELEASE across the Microservices.
I've bound a consumer using #EnableBinding annotation. The annotation will do rest of the part for me to consume events.
Some requirements came up to configure the topic name and some other configuration properties manually for which I want to override some of the properties of a consumer defined in an application.properties at application boot time.
Is there any direct way to do such?
You can use an initialization bean, it can do the work:
#SpringBootApplication
public class SpringDataDemoApplication {
#Bean
InitializingBean populateDatabase() {
return () -> {
// doWhatYouWantHere...
};
}

Spring-Boot module based integration testing

I have a multi-module Spring-Boot project.
I was wondering how I can set up integration testing just to test Spring Data JPA repositories? The following approach fails with this exception:
HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath.
Since this module does not depend on the web module, there is no web application that can be started.
#RunWith(SpringJUnit4ClassRunner.class)
#IntegrationTest
#SpringApplicationConfiguration(classes = TestConfiguration.class)
class CardInfoRepositoryIT {
#Autowired CardInfoRepository cardInfoRepository;
#Test
void testLoadData() {
assert cardInfoRepository.findAll().size() == 1
}
}
As Marten mentioned, #IntegrationTest should only be used when you need to test against the deployed Spring Boot application (e.g., deployed in an embedded Tomcat, Jetty, or Undertow container). So if your goal is to test your repository layer in isolation, you should not use #IntegrationTest.
On the other hand, if your tests require specific Spring Boot functionality (in contrast to standard Spring Framework functionality, semantics, and defaults), then you will in fact want to annotate your test class with #SpringApplicationConfiguration instead of #ContextConfiguration. The reason is that #SpringApplicationConfiguration preconfigures the SpringApplicationContextLoader which is specific to Spring Boot.
Furthermore, if you want your repository layer integration tests to run faster (i.e., without the full overhead of Spring Boot), you may choose to exclude configuration classes annotated with #EnableAutoConfiguration since that will auto-configure every candidate for auto-configuration found in the classpath. So, for example, if you just want to have Spring Boot auto-configure an embedded database and Spring Data JPA (with Hibernate as the JPA provider) along with entity scanning, you could compose your test configuration something like this:
#Configuration
#EnableJpaRepositories(basePackageClasses = UserRepository.class)
#EntityScan(basePackageClasses = User.class)
#Import({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
public class TestRepositoryConfig {}
And then use that configuration in your test class like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestRepositoryConfig.class)
#Transactional
public class UserRepositoryTests { /* ... */ }
Regards,
Sam
p.s. You might find my answer to the following, related question useful as well: Disable security for unit tests with spring boot
I resolved this by having the following test config class.
#Configuration
#EnableAutoConfiguration
#ComponentScan
#PropertySource("classpath:core.properties")
class TestConfiguration {
}
core.properties is also used by the main application and it contains datasource information. #IntegrationTest annotation can be removed on the test class.
I also added the following to the module as dependencies:
testRuntime 'javax.el:javax.el-api:2.2.4'
testRuntime 'org.glassfish.web:javax.el:2.2.4'

Resources