Could not autowire JobLauncherTestUtils - spring

I am attempting to test a simple spring batch application.
Using the Spring Batch documentation as a guide (found here), I have created the following test class:
import org.junit.runner.RunWith;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.context.SpringBatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.jupiter.api.Assertions.assertNotNull;
#SpringBatchTest
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = BatchConfig.class)
class BatchConfigTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Test
void userStep() {
assertNotNull(jobLauncherTestUtils, "jobLauncherTestUtils should not be null");
}
}
According to docs #SpringBatchTest should inject the JobLaucherTestUtils bean. However, when I run the test, the assertion fails. I have also tried defining the bean in an inner configuration class and had the same result:
static class TestConfiguration {
#Autowired
#Qualifier("userJob")
private Job userJob;
#Bean
public JobLauncherTestUtils jobLauncherTestUtils() {
JobLauncherTestUtils utils = new JobLauncherTestUtils();
utils.setJob(userJob);
return utils;
}
}
Is there something I'm missing? The full source code can be found here.

I am using Spring Batch v4.2.0 and JUnit 5
You are using #RunWith(SpringRunner.class) which is for JUnit 4. You need to use #ExtendWith(SpringExtension.class) for JUnit 5 tests:
#SpringBatchTest
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = BatchConfig.class)
class BatchConfigTest {
// ...
}

I had a same problem with Spring Batch 4.1.3 and JUnit 4.12.
Replacing #SpringBatchTest with #SpringBootTest solved the problem.

I was seeing the same error in IntelliJ and spent ages looking into why before I ran the test. It was being injected just fine, IntelliJ was incorrectly telling me the bean wasn't there.
:facepalm:
Posting this in case someone faces the same issue.

Related

I can't test on a test database during my integration tests

I would like to do some integration tests. These tests would then use a h2 test database, which would always be deleted afterwards.
Here is my test:
#SpringBootTest()
public class PostePomponServiceIT{
#Autowired
private PostePomponService postePomponService;
#Autowired
private PostePomponRepository postePomponRepository;
#Test
public void addPostePompon_Ok() throws BadRequestException {
PostePomponForm postePomponForm = new PostePomponForm();
postePomponService.add(postePomponForm);
assertEquals(1[![enter image description here][1]][1], postePomponRepository.findAll().size());
}
}
and my main test class:
package com.MailleCoTech.SuiviProduction;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.PropertySource;
#SpringBootTest(classes = SuiviProductionApplication.class)
#PropertySource("application-test.properties")
class SuiviProductionApplicationTests {
#Test
void contextLoads() {
}
}
My test-application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
and how my folder is structured:
My error is : com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
Remove annotation #SpringBootTest from test case. You have #DataJpaTest which does everything #SpringBootTest + some extra stuff(you can check documentation for more details).
The problem here is that you are using an empty #SpringBootTest.
but you also need to say the test which configuration classes you want to execute. I mean you say to the test "please execute a spring test", but you are not providing any spring application to it.
#SpringBootTest(classes={YourJavaClassWithStaticMain.class})
is what you want to do

#Autowired should not work without #RunWith(SpringRunner.class) but does

Here is a unit testing class for a java spring data repository layer.
I have a spring data repository layer in which the annotation #Autowired is used to inject TestEntityManager type object (belongs to spring data package).
The autowiring works whitout adding #RunWith(SpringRunner.class) annotation !
So what is the problem ? Well, I think that injection should not be possible whitout adding #RunWith(SpringRunner.class) annotation to the class : it should not work without it theorically.
How is it possible ? Does someone have any answer ?
>>>> view complete spring boot app code on github available here
Someone else have had the opposite problem in stackoverflow :
Someone else have had the opposite problem : see link here
Here is my strange bloc of code that amazingly that works :
package org.loiz.demo;
import org.assertj.core.api.BDDAssertions;
import org.junit.Assert;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test ;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Order ;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import demo.LoizBootSpringDemoApplication;
import demo.crepository.UserRepositoryInterface;
import demo.dmodel.User;
import demo.helper.helperUtils;
//Test de la couche de persistence
//#RunWith(SpringRunner.class)
#DataJpaTest
#ContextConfiguration(classes = { LoizBootSpringDemoApplication.class})
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
#SuppressWarnings("unused")
public class LoizPersistenceTest
{
#Autowired
private TestEntityManager testEntityManager;
#Autowired
private UserRepositoryInterface repository;
private static Long idStub ;
#Test
#Order(1)
#Rollback(false)
#DisplayName("Test de sauvegarde d\'un user \"prenom21 Nom21\"")
public void saveShouldMapCorrectly() throws Exception {
User userStub = new User("prenom21", "Nom21");
User UserSaved = this.testEntityManager.persistFlushFind(userStub);
BDDAssertions.then(UserSaved.getId()).isNotNull();
idStub = UserSaved.getId() ;
User UserRead = this.testEntityManager.find(User.class, idStub) ;
BDDAssertions.then(UserSaved.getFirstName()).isNotBlank();
BDDAssertions.then(UserSaved.getFirstName()).isEqualToIgnoringCase("prenom21");
BDDAssertions.then(UserSaved.getLastName()).isEqualToIgnoringCase("Nom21");
BDDAssertions.then(UserSaved.getLastName()).isNotBlank();
}
#Test
#Order(2)
#DisplayName("Test d'existence du user \"prenom21 Nom21\"")
public void readShouldMapCorrectly() throws Exception {
User userStub = new User(idStub, "prenom21", "Nom21");
User userFetched = this.testEntityManager.find(User.class, idStub) ;
String sUserStub = userStub.toString() ;
String sUserFetched = userFetched.toString() ;
boolean bolSameObject = userStub.equals(userFetched) ;
boolean bolAttrEgalEgal = sUserStub == sUserFetched ;
boolean bolStringEqual = sUserStub.equals(sUserFetched) ;
boolean bBeanUtil = helperUtils.haveSamePropertyValues (User.class,userStub,userFetched) ;
Assert.assertTrue(bBeanUtil);
}
}
Maybe it is normal, but what do i have to know ?
I would appreciate some answer please :)
>>>> view complete spring boot app code on github available here
#RunWith(SpringRunner.class) is used for junit 4 test.
But in our case, it is Junit 5 that is used. That is what we can see reading at the pom.xml file (using of junit.jupiter artifact proves that).
So #RunWith(SpringRunner.class) has no effects to manage spring container.
it should be replaced by #ExtendWith(SpringExtension.class).
HOWEVER :
#DataJpaTest already "contains" #ExtendWith(SpringExtension.class) !!!
So we don't need to add #ExtendWith(SpringExtension.class) when #DataJpaTest is used.
#DataJpaTest will allow to test spring data repository layer but will also guarantee spring dependency injection.
That is to say, and roughly speeking, you can use #Autowired annotation for a class which is annotated #DataJpaTest (a spring data repository layer).
From imports junit.jupiter i can see you are using junit-5, were #RunWith belongs to junit-4, and for reference #ExtendWith is not mandataroy for junit-5 test and if you want to use a specific runner you still require the #ExtendsWith but as #DataJpaTest itself is annotated with #ExtendsWith you don't need to do this explicitly
In JUnit 5, the #RunWith annotation has been replaced by the more powerful #ExtendWith annotation.
To use this class, simply annotate a JUnit 4 based test class with #RunWith(SpringJUnit4ClassRunner.class) or #RunWith(SpringRunner.class).

Why restTemplateBuilder is not loaded in Spring Boot 2.2.4?

I am trying to upgrade SpringBoot from 2.1.1 to 2.2.4.RELEASE.
I found an issue I can't solve.
When I try to run integration tests I run into an error:
Bean method 'restTemplateBuilder' in 'RestTemplateAutoConfiguration' not loaded because NoneNestedConditions 1 matched 0 did not; NestedCondition on RestTemplateAutoConfiguration.NotReactiveWebApplicationCondition.ReactiveWebApplication found ReactiveWebApplicationContext
This is my class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RoutesIT {
I noticed that a new #Conditional(NotReactiveWebApplicationCondition.class) is added to RestTemplateAutoConfiguration.class and this is probably the reason why restTemplateBuilder is not loaded properly.
I can create this bean manually but I don't think that's the best solution.
What should I do to make it work again?
Actually you should use WebClient instead of RestTemplate when you are reactive. See documentation here:
https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-client
But if you have other reasons to keep on using RestTemplate add this class into your test package:
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class TestConfiguration {
#Bean
public RestTemplateBuilder restTemplateBuilder() {
// Need to provide a rest template builder because
// #RestTemplateAutoConfiguration does not work with webflux
return new RestTemplateBuilder();
}
}

#SpyBean not working with Pact and JUnit 5

I'm trying to use the #SpyBean to mock a method of a #Component and doesn't work. #MockBean works (followed the example). I've tried, read and researched many ways but couldn't make it work.
Here's the example:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment. DEFINED_PORT)
#ExtendWith(SpringExtension::class)
#Provider("MyMicroService")
#PactFolder("../../../pacts")
internal class ClientContracts {
#SpyBean
private lateinit var myService: MyService
#TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider::class)
fun pactVerificationTestTemplate(context: PactVerificationContext) {
context.verifyInteraction()
}
#State("default", "NO_DATA")
fun toDefaultState() {
reset(processService)
}
}
(I super simplified the test function so it's easier to read, I'd be actually doing doReturn(...).when(...).blah())
I'm always getting the "not a mock" error, because the object is always the bean wrapped by Spring CGLIB:
org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class com.blah.MyServiceImpl$$EnhancerBySpringCGLIB$$9712a2a5
at com.nhaarman.mockitokotlin2.MockitoKt.reset(Mockito.kt:36)
...
I've tried:
with #SpringJUnitConfig
with a separate #TestConfiguration, but got resolved to same above bean
Using Mockito.initAnnotations(this) in a #BeforeEach
and more, I've tried with so many combinations that I can't remember...
Is there something that I'm missing? Or an option that I don't know?
Above issue is not related to the pact or pact JVM library
The issue is not about spring
Spring - I use spring with mockito and it works, the simple example is:
import com.nhaarman.mockito_kotlin.doReturn
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.SpyBean
import org.springframework.test.context.junit.jupiter.SpringExtension
#ExtendWith(value = [SpringExtension::class])
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = [Application::class]
)
internal class processorIntegrationTest : IntegrationTest() {
#SpyBean
// #MockBean
private lateinit var processor: Processor;
#Test
internal fun abcd() {
doReturn("something").`when`(processor).get()
val get = processor.get()
assertThat(get).isEqualTo("something")
}
}
Mockito - mockito_kotlin or mockito extension works with SpyBean
Issue is about mockito + CGLIB
CGLIB - from your logs feels like class com.blah.MyServiceImpl$$EnhancerBySpringCGLIB$$9712a2a5 there is a wrapper on top of your service implementation which is SpyBean.
Which means CGLIB wrapper is not and the error is for that.
Try removing CGLIB wrapper and it will work

Clear Spring application context after test

How can I clear the application context after each test execution, with Junit5 and Spring Boot? I want all beans created in the test to be destroyed after its execution, since I am creating the same beans in multiple tests. I don't want to have one configuration class for all tests, but configuration class per test, as shown bellow.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = MyTest.ContextConfiguration.class)
public class MyTest{
...
public static class ContextConfiguration {
// beans defined here...
}
}
Putting #DirtiesContext(classMode = BEFORE_CLASS) doesn't work with Junit5.
You have claimed twice that #DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) does not work; however, the following shows that it works as documented.
import javax.annotation.PreDestroy;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#ContextConfiguration
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
class MyTest {
#Test
void test1(TestInfo testInfo) {
System.err.println(testInfo.getDisplayName());
}
#Test
void test2(TestInfo testInfo) {
System.err.println(testInfo.getDisplayName());
}
#Configuration
static class Config {
#Bean
MyComponent myComponent() {
return new MyComponent();
}
}
}
class MyComponent {
#PreDestroy
void destroy() {
System.err.println("Destroying " + this);
}
}
Executing the above test class results in output to STDERR similar to the following.
test1(TestInfo)
Destroying MyComponent#dc9876b
test2(TestInfo)
Destroying MyComponent#30b6ffe0
Thus, #DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) is indeed how you "clear the application context after each test execution".
Putting #DirtiesContext(classMode = BEFORE_CLASS) doesn't work with Junit5.
Based on my testing, classMode = BEFORE_CLASS works with TestNG, JUnit 4, and JUnit Jupiter (a.k.a., JUnit 5).
So, if that does not work in your test class, that would be a bug which you should report to the Spring Team.
Do you have any example where you can demonstrate that not working?
FYI: using classMode = BEFORE_CLASS would only ever make sense if the context had already been created within the currently executing test suite. Otherwise, you are instructing Spring to close and remove an ApplicationContext from the cache that does not exist... just before Spring actually creates it.
Regards,
Sam (author of the Spring TestContext Framework)
According to the docs, try #DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)

Resources