Test Suite Run Spring Boot Once - spring

I am trying to create a test suite that runs Spring Boot once at the start of the suite. I have it working such that each test case has #SpringBootTest but I'd like to have #SpringBootTest in the test suite only.
I did see this but that didn't mentioned #RunWith Suite.class.

If I understood your question, for you launch many tests with spring boot you can do something like this:
1) First create yours tests classes. Here I have the first test class:
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace=Replace.NONE)
public class ExampleRepositoryTests {
#Autowired
private TestEntityManager entityManager;
#Autowired
private CustomerRepository repository;
#Test
public void testExample() throws Exception {
this.entityManager.persist(new Customer("sboot", "1234"));
Customer user = repository.findByFirstName("sboot").get(0);
assertThat(user.getFirstName()).isEqualTo("sboot");
}
}
2) My second test class.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace=Replace.NONE)
public class ExampleRepositoryTests2 {
#Autowired
private TestEntityManager entityManager;
#Autowired
private CustomerRepository repository;
#Test
public void testExample() throws Exception {
this.entityManager.persist(new Customer("sboot", "1234"));
Customer user = repository.findByFirstName("sboot").get(0);
assertThat(user.getFirstName()).isEqualTo("sboot");
}
}
3) Now let's create the suite test class:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
#RunWith(Suite.class)
#Suite.SuiteClasses({
ExampleRepositoryTests.class, //test case 1
ExampleRepositoryTests2.class //test case 2
})
public class AppTest {
}
You can start each test separately, but, if you start the suite test, the class will start every tests declared in #Suite.SuiteClasses.
These tests I am using just Spring JPA and Spring Boot. It is importante you have the dependencies in your project. Below you can see my maven dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Note that I am testing JPA Data Classes (#DataJpaTest). For others test types you will using others Spring annotations. You can see some documentation about this here.
I hope help you! o/

Related

Consider defining a bean of type 'org.springframework.cloud.openfeign.FeignContext' in your configuration

I am trying to run the application but this error keeps prompting.
Description:
Parameter 0 of constructor in com.clientui.clientui.controller.ClientController required a bean of type 'org.springframework.cloud.openfeign.FeignContext' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.cloud.openfeign.FeignContext' in your configuration.
Here is the code:
Main
package com.clientui.clientui;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#SpringBootApplication
#EnableFeignClients("com.clientui")
public class ClientuiApplication {
public static void main(String[] args) {
SpringApplication.run(ClientuiApplication.class, args);
}
}
Controller
package com.clientui.clientui.controller;
import com.clientui.clientui.beans.ProductBean;
import com.clientui.clientui.proxies.MicroserviceProduitsProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
#Controller
public class ClientController {
private final MicroserviceProduitsProxy produitsProxy;
public ClientController(MicroserviceProduitsProxy produitsProxy){
this.produitsProxy = produitsProxy;
}
#RequestMapping("/")
public String accueil(Model model){
List<ProductBean> produits = produitsProxy.listeDesProduits();
model.addAttribute("produits", produits);
return "Accueil";
}
}
I had the same problem when updating the spring-boot version to 3.0.0, I think it's some compatibility bug with spring cloud and spring boot's autoconfigure.
I solved it by adding the annotation #ImportAutoConfiguration({FeignAutoConfiguration.class}) in the application, in your case:
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
#SpringBootApplication
#EnableFeignClients("com.clientui")
#ImportAutoConfiguration({FeignAutoConfiguration.class})
public class ClientuiApplication {
public static void main(String[] args) {
SpringApplication.run(ClientuiApplication.class, args);
}
}
I use Spring Boot 3.0.0 and faced the same issue and resolved it by using 2022.0.0-RC2 version of spring-cloud-dependencies. (https://docs.spring.io/spring-cloud/docs/2022.0.0-RC2/reference/html/). It should work with Spring Boot 3.0.0.
If you are using Maven add this to your dependencyManagement section in pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2022.0.0-RC2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Note: For the time I am writing this answer 2022.0.0-RC2 version is not available in central repository but you can find it in Spring Lib M repository so you should also add it to your repositories section in pom.xml:
<repository>
<id>lib-m</id>
<name>Spring Lib M</name>
<url>https://repo.spring.io/libs-milestone/</url>
</repository>
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
#ImportAutoConfiguration({FeignAutoConfiguration.class})
Adding these line on main app fixes the issue.
If you are using Spring 3.0.0 the "spring.factories" has been removed. The automatic import of autoconfigurations is broken if your dependency uses this.
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#auto-configuration-files
The one way to fix this on your side without modifying the dependecy itself is using #ImportAutoConfiguration({ list of autoconfiguration classes }) explicitly. You can also use new functionality "imports file" provided by Spring. The right way is to migrate "spring.factories" to "imports file" on the dependency side.

Unable to get table autocreated in spring module integration test

I have a parameters module in my project which other modules are dependent on. I'd like to write instegration tests for this module in separate manner. This module is a spring based one and has some db related logic, though db migration scripts are not available in this module since it is something that is out of its area of resposibility. By the way in-memory H2 instance is used for testing purposes.
What I'm trying to achieve is to make spring/hibernate create DB tables based on single #Entity class present in this module, it is called ParameterEntity.
It is defined like this:
#Entity
#Table(name = "SYSTEM_PARAMETERS")
public class ParameterEntity {
#Id
#Column(name = "id")
private String id;
#Column(name = "value")
private String value;
// accessors go here...
}
In my application-test.yml file I provide the following props:
spring:
jpa:
hibernate:
ddl-auto: create
database: h2
show-sql: true
And define integration test class like this:
#ExtendWith(SpringExtension.class)
#EnableConfigurationProperties
#EntityScan("path.to.package.where.parameter.entity.resides")
#ConstextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
#ActiveProfiles("test")
#TestInstance(Lifecycle.PER_CLASS)
public class ParametersIntegrationTest {
#Autowired
private ParameterWarden warden;
#BeforeEach
public void setUp() {
warden.initialize();
}
#Configuration
#ComponentScan("base.module.package")
static class TestConfiguration {
// here comes some test beans which will be used in testing purposes only
}
}
In #BeforeEach method ParameterWarden class calls repository class which in turn make some calls to database to retrieve parameter entities from database and these calls fail because SYSTEM_PARAMETERS is missing.
Could anyone, please, let me know what am I missing here and how can I make spring or hibernate create table based on the entity present in my project. Even the place where I can debug this would be nice to know.
It seems like I need another magical thing that will trigger this functionality but I was unable to figure out what exactly I need.
Any help is really appreciated, thank you very much for your time!
p.s. I can not use #SpringBootTest annotation since this module uses only some spring features and is not a spring boot application itself. It is used as a dependecy in another spring boot applications.
Can you still use #DataJpaTest?
package com.test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#DataJpaTest
#ContextConfiguration(classes = TestEntityRepository.class)
#TestPropertySource(properties = {
"spring.jpa.hibernate.ddl-auto=create",
"spring.datasource.platform=h2",
"spring.jpa.show-sql=true"
})
#EnableAutoConfiguration
public class IntegrationTest {
#Autowired
TestEntityRepository testEntityRepository;
#Test
void testCreateRead() {
var saved = testEntityRepository.save(new TestEntity("test"));
Assertions.assertNotNull(saved);
var read = testEntityRepository.findById(saved.getId());
Assertions.assertNotNull(read);
}
}
Where repository and entity in the com.test package are:
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface TestEntityRepository extends CrudRepository<TestEntity, Long> { }
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
#Entity
#Data
#NoArgsConstructor
public class TestEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column
private Long id;
#Column
private String attr;
public TestEntity(String attr) {
this.attr = attr;
}
}
Dependecies used (through dependency management and Spring Boot BOM of version 2.3.4.RELEASE):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Alternatively, if you want to fully decouple tests from Spring you can use org.hibernate.tool.hbm2ddl.SchemaExport in some utility logic since that's what's really executing under the hood. I use this approach since my project requires some extra steps to setup the database, however, it might be too complicated for some use cases.

CrudRepository class is not available int my spring boot project how can i resolve this problem

package com.example.repo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.example.dto.Student;
#Repository
public class StudentRepository extends CrudRepository<Student, Integer> {
}
If you want a Repository managed by Spring when using the spring-boot-starter-data-jpa, also called InstantRepository you need to create an interface, not a class. You don't need the #Repository annotation either.
package com.example.repo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.example.dto.Student;
public interface StudentRepository extends CrudRepository<Student, Integer> {}
Make sure com.example.repo is a sub-package of your #SpringBootApplication class.
CrudRepository is a part of spring-boot-starter-data-jpa.
So add it as a dependency to your build. For maven build it'll be:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Integration test with jersey and spring boot 1.4.0.RELEASE

I am trying to write integration test with jersey, Spring boot 1.4 and Spring data jpa.I am able to start embedded server but getting error from jersey side , any help will be appreciated.
Integration test
import static org.assertj.core.api.Assertions.assertThat;
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.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT, classes=Application.class)
public class ContactServiceIT {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private ContactDao contactDao;
#Test
public void mergeContactsTest() {
String body = this.restTemplate.getForObject("/contacts/merge", String.class);
assertThat(body).isEqualTo("contacts merged");
}
}
Contact Resource
import java.io.IOException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
#Path("/contacts")
public class ContactResource {
#Autowired
private ContactService contactService;
#GET
#Path("merge")
public Response mergeContacts() throws IOException {
contactService.mergeContacts();
return Response.status(Response.Status.CREATED)
.entity("contacts merged").build();
}
}
Stack trace:
java.lang.NoSuchMethodError: org.glassfish.jersey.CommonProperties.getValue(Ljava/util/Map;Ljavax/ws/rs/RuntimeType;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
at org.glassfish.jersey.jackson.JacksonFeature.configure(JacksonFeature.java:73) ~[jersey-media-json-jackson-2.23.1.jar:na]
at org.glassfish.jersey.model.internal.CommonConfig.configureFeatures(CommonConfig.java:680) ~[jersey-common-2.7.jar:na]
at org.glassfish.jersey.model.internal.CommonConfig.configureMetaProviders(CommonConfig.java:610) ~[jersey-common-2.7.jar:na]
at org.glassfish.jersey.server.ResourceConfig.configureMetaProviders(ResourceConfig.java:800) ~[jersey-server-2.7.jar:na]
Please let me know if I am missing something.
Thanks.

Unable to inject dependency in Junit test

Having some trouble injecting a dependency in one of my JUnit test classes.
I believe the TestApplication is not package scanning or is not being loaded.
Code below:
package com.mitto.repositories;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import com.github.springtestdbunit.DbUnitTestExecutionListener;
import com.github.springtestdbunit.annotation.DatabaseSetup;
import com.mitto.MittoApplicationTests;
import com.mitto.domain.User;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration( classes= { MittoApplicationTests.class } )
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
TransactionalTestExecutionListener.class,
DbUnitTestExecutionListener.class})
#DatabaseSetup("UserRepositoryTest.xml")
public class UserRepositoryTest {
#Autowired
UserRepository repository;
private static final long FACEBOOK_ID = 1234567;
#Test
public void getUserById() {
User user = repository.findOne(1L);
assertNotNull(user);
assertEquals( user.getFacebookId(), FACEBOOK_ID );
}
}
MittoApplicationTests.java
package com.mitto;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class MittoApplicationTests {
#Test
public void contextLoads() {
}
}
UserRepository.java
package com.mitto.repositories;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.mitto.domain.User;
#Repository
public interface UserRepository extends PagingAndSortingRepository<User, Long>{
User findByFacebookId( long facebookId );
User findByAuthToken( String token );
}
I can't see anything wrong with this.
Sometimes, a working example is better than fixes.
Here is a working example:
First, in your configuration class
#SpringBootApplication
#ComponentScan(value = "com.mitto")
#EnableJpaRepositories(value = "com.mitto")
#EntityScan(basePackages = {"com.mitto.domain"}, basePackageClasses = {Jsr310JpaConverters.class})
public class MittoApplicationTests {
}
Second, in your test class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = MittoApplicationTests.class) // replace the #ContextConfiguration with #SpringBootTest
// rest of of your annotations ...
public class UserRepositoryTest {
#Autowired
UserRepository repository;
// your test cases
}
A Spring Boot application is just a Spring ApplicationContext, so nothing very special has to be done to test it beyond what you would normally do with a vanilla Spring context. One thing to watch out for though is that the external properties, logging and other features of Spring Boot are only installed in the context by default if you use SpringApplication to create it.
Spring Boot provides a #SpringBootTest annotation which can be used as an alternative to the standard spring-test #ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests via SpringApplication.
Please read the documentation for more details:
SpringBootTest annotation
boot-features-testing

Resources