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
Related
I have a Spring Boot web application that I launch by running this class ...
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The web app has a JSP/HTML front end served up by Spring MVC Controllers which talk to Services which talk to DAOs which uses Hibernate to read/write Entities to a MySQL database.
All the components and services get instantiated and #Autowired and the web app runs fine.
Now, I want to build JUnit tests and test some of the functionality in the Services or the DAOs.
I started writing a JUnit test like below, but I quickly got stuck on not knowing how to instantiate all the #Autowired components and classes.
public class MySQLTests {
#Test
public void test000() {
assertEquals("Here is a test for addition", 10, (7+3));
}
#Autowired
UserService userService = null;
#Test
public void test001() {
userService.doSomething("abc123");
// ...
}
}
I basically want the web application to start up and run, and then have the JUnit tests run the methods in those Services.
I need some help getting started ... is there some kind of JUnit equivalent of the #SpringBootApplication annotation that I can use in my JUnit class?
Answering my own question ... I got it working like this ...
Annotated the test class with:
#RunWith(SpringRunner.class)
#SpringBootTest
The test class had to be in a package above the #Controller class ... so my test class is in com.projectname.* and the controller is is com.projectname.controller.*
The working code looks like this ...
package com.projectname;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.projectname.controller.WebController;
#RunWith(SpringRunner.class)
#SpringBootTest
public class Test1 {
#Autowired
private WebController controller;
#Test
public void contextLoads() throws Exception {
assertNotNull("WebController should not be null", controller);
}
}
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).
I am using spring boot integration test with h2 database and testNg for integration tests.
And my spring boot application uses spring data jpa.
For each test, i am unable to see data saved by the previous tests.
Below is my Integration test class:-
import org.springframework.test.annotation.Rollback;
import org.testng.annotations.Test;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
#ActiveProfiles("test")
#SpringBootTest(classes = APP.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class IntegrationTest extends AbstractTestNGSpringContextTests {
#Test(priority = 1)
#Rollback(false)
private void m1() {
// save data.
}
#Test(priority = 1)
#Rollback(false)
private void m2() {
// retrieve saved data. (Failed)
}
}
I am using TestRestTemplate to test test PUT and POST Rest endpoints.
You are using #SpringBootTest annotation, which means you will start an entire spring-boot application. #Commit and #Rollback are to use with #DataJpaTest, or something similar, when your test is #Transactional to have a good control.
Here is what I think:
Either there is a problem with TestNG and Spring, in which case, there is not much I can do
Or your code is in fault. Have you tried using some breakpoints to see if your code goes through all your layers.
Could you show more of your code ? The test code, the controller, the service and data layer. And of course, your configuration classes, that would be great in order to help
You have to use the annotation #Commit and not #Rollback
#ActiveProfiles("test")
#SpringBootTest(classes = APP.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public class IntegrationTest extends AbstractTestNGSpringContextTests {
#Test
#Commit
private void m1() {
}
}
Alternatively, you could use TransactionTemplate for a more grained control. See this: How to force transaction commit in Spring Boot test?.
Execute your repository calls within a transaction.
final TransactionTemplate transactionTemplate = new TransactionTemplate(txManager);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
return transactionTemplate.execute(new TransactionCallback<R>() {
#Override
public R doInTransaction(final TransactionStatus status) {
myRepository.save(myEntity);
}
});
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.
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)