Junit tests are failing after moving from spring boot 2.5.* to 2.6.* - spring

I am working on moving my kafa CDC application to spring boot 2.6.* . But when I upgrade to spring boot 2.6.*, Junit tests are failing with following error
CdcConsumerApplicationTest > testMainApplicationLoad() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
Caused by: java.lang.IllegalStateException at SpringBootCondition.java:60
Caused by: java.lang.ArrayStoreException at AnnotationParser.java:724
This is simple Junit example test that is failing
#SpringBootTest
#ActiveProfiles("test")
#ContextConfiguration(classes = { AppTestConfiguration.class })
#EmbeddedKafka(partitions = 1, topics = { "XXX.SOME-DB2-CHANGE" })
public class CdcConsumerApplicationTest {
#Test
public void testMainApplicationLoad() {
}
}
If I run this tests locally on my IDE, they works fine but they are failing when running via jenkins. All my Junits are junit 5. Anything I am missing or I need to change when moving from spring boot 2.5 to 2.6 and further ?

Related

Spring Boot 3 with Kotlin throws java.lang.UnsupportedOperationException for data class on GraalVM

Trying to run a very simple Spring Boot 3 app on GraalVM. The app just stores some data in H2 on startup. It is basically the same as what Josh does in the Spring Tips about Ahead-of-Time compilation, but using Kotlin instead of Java.
When starting the native image, I get the following error after Spring startup:
java.lang.UnsupportedOperationException: Kotlin class com.example.demo.basics.Customer has no .copy(…) method for property id
at org.springframework.data.mapping.model.BeanWrapper$KotlinCopyUtil.setProperty(BeanWrapper.java:171) ~[na:na]
at org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:79) ~[na:na]
...
I'm pretty new to GraalVM and Spring Native Images, don't know if I am missing something basic which needs to be configured when using Kotlin with Spring. The missing copy methods for the data class should have been generated by Kotlin, so I guess something is left out by the native compile related to Kotlin specifically.
The code which fails is the following class:
#Configuration
class BasicsConfiguration {
#Bean // execute on application start
fun basicsApplicationListener(customerRepository: CustomerRepository): ApplicationListener<ApplicationReadyEvent> {
return ApplicationListener<ApplicationReadyEvent> {
// store some values in the database
customerRepository
.saveAll(listOf("A", "B", "C").map { Customer(null, it) })
.forEach { println(it) }
}
}
}
interface CustomerRepository : CrudRepository<Customer, Int>
data class Customer(#Id val id: Long?, val name: String)
Running the app on the JDK works perfectly fine: ./gradlew bootRun
2022-11-30T11:23:15.300+01:00 INFO 33997 --- [ main] com.example.demo.DemoApplicationKt : Started DemoApplicationKt in 2.383 seconds (process running for 2.733)
Customer(id=1, name=A)
Customer(id=2, name=B)
Customer(id=3, name=C)
The native image is also created successfully: ./gradlew nativeCompile
Starting the native image works, the server process starts up but then fails:
2022-11-30T11:08:11.085+01:00 INFO 33059 --- [ main] com.example.demo.DemoApplicationKt : Started DemoApplicationKt in 0.147 seconds (process running for 0.158)
2022-11-30T11:08:11.089+01:00 ERROR 33059 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.UnsupportedOperationException: Kotlin class com.example.demo.basics.Customer has no .copy(…) method for property id
at org.springframework.data.mapping.model.BeanWrapper$KotlinCopyUtil.setProperty(BeanWrapper.java:171) ~[na:na]
at org.springframework.data.mapping.model.BeanWrapper.setProperty(BeanWrapper.java:79) ~[na:na]
...
Seems like this is an issue with Spring Data, which is not providing all necessary reflection hints for the native image creation. Specifically the reflection configuration for data classes' copy$default methods are missing. Will (probably) be fixed with Spring 6.0.3 release, see this issue for details: https://github.com/spring-projects/spring-framework/issues/29593
Workaround: add something like this in your reflect-config.json for the given data class:
{
"name": "copy$default",
"parameterTypes": [
"com.example.demo.basics.Customer",
"java.lang.Long",
"java.lang.String",
"int",
"java.lang.Object"
]
}

No qualifying bean of type 'org.springframework.cloud.stream.binder.test.OutputDestination' available

I am trying to use spring cloud contracts for messaging.
I have a producer and a consumer who is publishing and consuming from rabbitmq.
they are working fine when I run both these spring boot applications.
however, when I try to mvn clean install , generated ContractVerifierTest fails with the error
2022-01-18 14:35:55.982 ERROR 62575 --- [ main] s.StreamOutputDestinationMessageReceiver : Exception occurred while trying to read a message from a channel with name [fraud]
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.stream.binder.test.OutputDestination' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351) ~[spring-beans-5.3.14.jar:5.3.14]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342) ~[spring-beans-5.3.14.jar:5.3.14]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1172) ~[spring-context-5.3.14.jar:5.3.14]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamOutputDestinationMessageReceiver.receive(StreamOutputDestinationMessageReceiver.java:43) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamOutputDestinationMessageReceiver.receive(StreamOutputDestinationMessageReceiver.java:55) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamOutputDestinationMessageReceiver.receive(StreamOutputDestinationMessageReceiver.java:30) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamStubMessages.receive(StreamStubMessages.java:59) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.stream.StreamStubMessages.receive(StreamStubMessages.java:31) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
at org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierMessaging.receive(ContractVerifierMessaging.java:65) ~[spring-cloud-contract-verifier-3.1.0.jar:3.1.0]
I have spring-cloud-stream, spring-cloud-stream-binder-rabbit, spring-cloud-starter-contract-verifier, spring-cloud-stream:test-binder dependencies in my pom as well.
My spring boot application class is configured like this
#SpringBootApplication
#EnableBinding(Source.class)
public class ProducerApplication {
It is sending the message to the destination topic from tests as well. However, it fails to read it
#Test
public void validate_contract_name() throws Exception {
// when:
trigger(); // this happens fine
// then:
ContractVerifierMessage response = contractVerifierMessaging.receive("destination-name",
contract(this, "contract_name.yml")); // THIS FAILS
assertThat(response).isNotNull();
I have annotated my base test class with these
#SpringBootTest(classes = ProducerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
#ExtendWith(SpringExtension.class)
#AutoConfigureMessageVerifier
I have verified that OutputDestination class is available in the classpath.
I have org.springframework.cloud:spring-cloud-stream:test-jar:test-binder:3.2.1:test in the classpath.
spring-boot-starter-parent version is 2.6.2. spring cloud version is 2021.0.0
I have configured spring-cloud-contract-maven-plugin version 3.1.0 to use JUNIT5

Kotlin integration Tests with Spring Boot

What I have: I'm developing a microservice, using Spring Boot with Web and MongoDB as storage. For CI integration tests I use test containers. I have two integrations tests with SpringBootTest annotations, which use TestConfig class. TestConfig class provides setup MongoDB test container with fixed exposed ports.
My problem: When I run my tests one at a time then they succeed. But when I run my tests at the same time then they failed.
MongoContainerConfig.kt
#TestConfiguration
class MongoContainerConfig {
var mongoContainer: GenericContainer<Nothing>
constructor() {
mongoContainer = FixedHostPortGenericContainer<Nothing>("mongo")
.withFixedExposedPort(27018,27017)
mongoContainer.start()
}
#PreDestroy
fun close() {
mongoContainer.stop()
}
}
First test
#SpringBootTest(
classes = arrayOf(MongoContainerConfig::class, AssertUtilsConfig::class),
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
class CardControllerTest {
#Test
fun test() {}
}
Second test
#SpringBootTest(classes = arrayOf(MongoContainerConfig::class, AssertUtilsConfig::class))
class PositiveTest {
#Test
fun test() {}
}
Error msg
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoContainerConfig': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.lang.card.engcard.config.MongoContainerConfig$$EnhancerBySpringCGLIB$$e58ffeee]: Constructor threw exception; nested exception is org.testcontainers.containers.ContainerLaunchException: Container startup failed
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1320)
a
This project you can see on github with CI
https://github.com/GSkoba/eng-card/runs/576320155?check_suite_focus=true
It's very funny because tests work if rewrite them to java
Hah, it not easy)
https://docs.spring.io/spring/docs/5.2.5.RELEASE/spring-framework-reference/testing.html#testcontext-ctx-management-caching
Tests have different context and its why MongoContainerConfig call twice.
Fix - add webEnv as in CardControllerTest.kt
#SpringBootTest(classes = arrayOf(MongoContainerConfig::class, AssertUtilsConfig::class),
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class PositiveTest
Proof https://github.com/GSkoba/eng-card/actions/runs/78094215

Unable to call Mapper.xml file by using junit testing for the application developed using Mybatis+Springboot

I'm very new to junit testing. How to write junit test real database call from mybatis.xml file.
Please find the below code.
#RunWith(SpringRunner.class)
//#MybatisTest
#SpringBootTest
public class HotelMapperTest {
#Autowired
private HotelMapper hotelMapper;
#Test
public void selectByCityIdTest() {
Hotel hotel = hotelMapper.selectByCityId(1);
assertThat(hotel.getName()).isEqualTo("Conrad Treasury Place");
assertThat(hotel.getAddress()).isEqualTo("William & George Streets");
assertThat(hotel.getZip()).isEqualTo("4001");
}
when i run the junit testing i'm getting below exception:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
Herer my question is how we'll test the real database, When enable the #MybatisTest it's looking for datasource, already we specified all properties in applicaiton.properties. In this time i'm getting below exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource':
You can config mybatis mapper location in spring configuration file (such as application.yml).
mybatis configuration:
mybatis:
mapper-locations:
- classpath*:mapper/*.xml

DI in tests without using spring boot (#SpringBootTest)

Switching from spring boot back to "normal" spring because the app only uses some jdbc code to "upsert" into a postgresql database.
1)
tried annotating the test class with:
#RunWith(SpringJUnit4ClassRunner.class)
public class DBIntegration {
results in:
java.lang.IllegalStateException: Failed to load ApplicationContext
2)
tried annotating the class with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {})
public class DBIntegration {
[main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [de.mydomain.myproject.DBIntegration]: no resource found for suffixes {-context.xml}.
No exceptions, but java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=insertDataFrom_sometest],
3) tried annotating the class with:
#Component
public class DBIntegration {
dependency injection does not work in this case, the expected service
(to be injected) throws a nullpointerexception

Resources