Integration Testing With #DataJpaTest - spring-boot

I have this test in my project:
#DataJpaTest
#SpringBootTest
#TestPropertySource(locations = "classpath:local-configuration.properties")
public class CanPixaRepositoryTest {
#Autowired
private CanPixaRepository canPixaRepository;
public void setUp() throws Exception {
}
#Test
public void testAll() {
canPixaRepository].getAvui("fqs");
}
}
local-configuration.properties:
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
but when I run the test, canPixaRepositoryRepository is null

For Spring boot applications, the simplest approach is using #DataJpaTest with H2 to test your repositories if you are using JPA and Spring Data JPA.
Add h2 dependency into your test scope. Spring Boot will auto-configure it and use it to replace the runtime DataSource in the testing phase.
Annotate your tests with #DataJpaTest. Then the EntityManager, your repositories, and a test-purpose TestEntityManager are available in the Spring Application Context.
Check my example here.
(Spring 5/Spring Boot 2 added Junit 5 support, it does not require the #Runwith or #Extendwith if you are using Junit 5 integration, the DataJpaTest itself is a meta-annotation, before Spring 2.4, to enable Junit5, you have to exclude JUnit 4 from spring-boot-test and add JUnit 5 manually. In the upcoming Spring Boot 2.4, JUnit 5 is the default test runner)

#SpringBootTest annotation is used to setup the entire application context while the #DataJpaTest will setup the application context so that you could test your jpa related code, it will setup a slice of your application context for this specific use case .So there is no need to use the #SpringBootTest annotation with #DataJpaTest, use it like :
#ExtendWith(SpringExtension.class)
#DataJpaTest
#TestPropertySource(locations = "classpath:local-configuration.properties")
public class CanPixaRepositoryTest {
#Autowired
private CanPixaRepository canPixaRepository;
public void setUp() throws Exception {
}
#Test
public void testAll() {
canPixaRepository.getAvui("fqs");
}
}
Since SpringBoot 2.1 you don't have to provide the #ExtendWithannotation to tell Junit to enable spring support as it is already provided with the annotations like #SpringBootTest and #DataJpaTest.

Related

PostConstruct and test

I use spring boot 3
Main spring boot class
#EnableTransactionManagement
#SpringBootApplication
#Slf4j
public class FlexApplication{
private final ApplicationParameterManager appParamManager;
public FlexApplication(ApplicationParameterManager appParamManager) {
this.appParamManager = appParamManager;
}
#PostConstruct
public void init(){
}
....
}
#Service
#Slf4j
public class ApplicationParameterManager{
....
}
Basic test
#AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
#DataJpaTest
public class ListUserRepositoryTest {
#Autowired
private ListUserRepository repository;
#Test
public void getListUserByUserType(){
String typeUser = "CETEST";
Pageable page = Pageable.ofSize(10);
Page<ListUser> pageListUser = repository.findAllByTypeUser(typeUser, page);
assertThat(pageListUser.getContent().size() > 5 ).isTrue();
}
}
Otherwise this test, application run well
I get this error
Parameter 0 of constructor in com.acme.FlexApplication required a bean
of type 'com.acme.parameter.ApplicationParameterManager' that could
not be found.
I think it is not related to version of Spring Boot.
As you're using #DataJpaTest , your bean is not created
Spring Docs:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.
Solution would be to use #SpringBootTest instead of #DataJpaTest if your test is not really a JPA test.
Also, still using #DataJpaTest you could add #Import(ApplicationParameterManager.class) to your test class
When using #DataJpaTest, you are not creating the whole spring context as when you run the application normally but you only create the beans responsible for data access layer.
In order to run your tests properly, you need to provide a mocked bean of type ApplicationParameterManager.
The easiest way to do it is by utilizing #MockBean annotation.
So, to make your tests work, edit the test in the following way.
#AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
#DataJpaTest
public class ListUserRepositoryTest {
#MockBean
private ApplicationParameterManager applicationParameterManager;
#Autowired
private ListUserRepository repository;
#Test
public void getListUserByUserType(){
String typeUser = "CETEST";
Pageable page = Pageable.ofSize(10);
Page<ListUser> pageListUser = repository.findAllByTypeUser(typeUser, page);
assertThat(pageListUser.getContent().size() > 5 ).isTrue();
}
}
That way, the spring context will include a mocked bean of your required dependency.
Take a look at #MockBean java doc for more information. https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html
If you prefer to run the whole spring context in order to perform full integration tests, take a look at #SpringBootTest annotation.
#DataJpaTest should be used when you want to test data access layer in isolation.

How to inject values from application.yaml to Junit 5 Test case

I am using Junit5 to write unit test cases in java. I have few values that I have added in application.yaml but I am not able to retrieve them in my test file eg. ownerMasterList value is coming as null but it is present in application.yaml
#ExtendWith(MockitoExtension.class)
public class OwnerServiceTest {
#Value("${owner.master-list}")
private ownerMasterList;
#Test
void findAllOwners(){
---test detail
}
}
Using ConfigFileApplicationContextInitializer alone does not provide support for #Value("${…​}") injection. Its only job is to ensure that application.properties files are loaded into Spring’s Environment. For #Value support, you need to either additionally configure a PropertySourcesPlaceholderConfigurer or use #SpringBootTest, which auto-configures one for you.
From doc
#RunWith(SpringRunner.class)
#ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
public class OwnerServiceTest {...}
Please try providing property source
By reading your code, it seems that you are using JUnit5 (#ExtendWith(MockitoExtension.class)).
The correct extension to use to trigger the launch of a Spring application context is (#ExtendWith(SpringExtension.class)). If you are using Spring Boot, you can use the #SpringBootTest annotation which is itself annotated with #ExtendWith(SpringExtension.class).
One point to note though: you should not wire an application context when unit testing your code. You should rather test your class in isolation and inject the needed property (here ownerMasterList) through the constructor (see #BeforeEach JUnit 5 annotation):
class OwnerServiceTest {
private OwnerService ownerService;
#BeforeEach
void setUp() {
this.ownerService = new OwnerService(new ArrayList<>(...));
}
}

Spring boot cucumber testing

I try to perform some Cucumber tests of a Spring boot application.
It seems like Spring Boot is not started before tests are running.
What am i missing?
https://bitbucket.org/oakstair/spring-boot-cucumber-example
My Cucumber repo still runs without doing all the above steps:
https://github.com/BarathArivazhagan/Cucumber-spring-integration
Docs : https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
To add more:
#SpringBootTest takes care of loading the application context in that case #ContextConfiguration is reductant.
Spring test automatically provides a bean of TestRestTemplate which can be autowired but still it should work with RestTemplate also.
It still runs without RANDOM_PORT but RANDOM port can be also used in conjunction for testing.
Let's say you have a feature file, feature1, and glueCode in org.xyz.feature1
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty"},
features = "src/test/java/resources/feature/feature1",
glue = {"org.xyz.feature1"})
public class CucumberTest {
}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {Application.class},
webEnvironment = WebEnvironment.RANDOM_PORT)
#ContextConfiguration
#Ignore
#Transactional
public class FeatureTest extends CucumberTest {
#LocalServerPort
int randomServerPort;
#Given("........")
public void test_1 {
}
}
I found the problem and has updated the repo.
I did the following to get it working:
Added RANDOM_PORT to #SpringBootTest
Added #ContextConfiguration
Switched from RestTemplate to TestRestTemplate

How to exclude/disable a specific auto-configuration in Spring boot 1.4.0 for #DataJpaTest?

I am using the #DataJpaTest from Spring for my test which will then use H2 as in memory database as described here . I'm also using Flyway for production. However once the test starts FLyway kicks in and reads the SQL file. How can I exclude the FlywayAutoConfiguration and keep the rest as described here in spring documentation in order to let Hibernate create the tables in H2 for me?
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private MyRepository triggerRepository;
}
Have you tried the #OverrideAutoConfiguration annotation?
It says it "can be used to override #EnableAutoConfiguration".
I'm assuming that from there you can somehow exclude FlywayAutoConfiguration
like so:
#EnableAutoConfiguration(exclude=FlywayAutoConfiguration.class)
Adding the dependency on an in-memory database to my build.gradle
e.g. testRuntime "com.h2database:h2:1.4.194"
And adding flyway.enabled=false to application.properties in src/test/resources worked for me.
I am converting an old JDBC app into a spring-data-jpa app and I'm working on the first tests now. I kept seeing a security module instantiation error from spring-boot as it tried to bootstrap the security setup, even though #DataJpaTest should theoretically be excluding it.
My problem with the security module probably stems from the pre-existing implementation which I inherited using PropertySourcesPlaceholderConfigurer (via my PropertySpringConfig import below)
Following the docs here:
http://docs.spring.io/spring-boot/docs/1.4.x/reference/htmlsingle/#test-auto-configuration
and your comments on #LiviaMorunianu's answer, I managed to work my way past every spring-boot exception and get JUnit to run with an auto-configured embedded DB.
My main/production spring-boot bootstrap class bootstraps everything including the stuff I want to exclude from my tests. So instead of using #DataJpaTest, I copied much of what it is doing, using #Import to bring in the centralized configurations that every test / live setup will use.
I also had issues because of the package structure I use, since initially I was running the test which was based in com.mycompany.repositories and it didn't find the entities in com.mycompany.entities.
Below are the relevant classes.
JUnit Test
#RunWith(SpringRunner.class)
#Transactional
#Import({TestConfiguration.class, LiveConfiguration.class})
public class ForecastRepositoryTests {
#Autowired
ForecastRepository repository;
Forecast forecast;
#Before
public void setUp() {
forecast = createDummyForecast(TEST_NAME, 12345L);
}
#Test
public void testFindSavedForecastById() {
forecast = repository.save(forecast);
assertThat(repository.findOne(forecast.getId()), is(forecast));
}
Live Configuration
#Configuration
#EnableJpaRepositories(basePackages = {"com.mycompany.repository"})
#EntityScan(basePackages = {"com.mycompany.entity"})
#Import({PropertySpringConfig.class})
public class LiveConfiguration {}
Test Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestConfiguration {
// lots of bean definitions...
}
PropertySpringConfig
#Configuration
public class PropertySpringConfig {
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
throws IOException {
return new CorePropertySourcesPlaceholderConfigurer(
System.getProperties());
}
}
In my particular case, i needed to disable the FlywayDB on in-memory integration tests. These are using a set of spring annotations for auto-configuring a limited applicationContext.
#ImportAutoConfiguration(value = TestConfig.class, exclude = FlywayAutoConfiguration.class)
the exclude could effectively further limit the set of beans initiated for this test
I had the same problem with my DbUnit tests defined in Spock test classes. In my case I was able to disable the Flyway migration and managed to initialize the H2 test database tables like this:
#SpringBootTest(classes = MyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = ["flyway.enabled=false", "spring.datasource.schema=db/migration/h2/V1__init.sql"])
I added this annotation to my Spock test specification class. Also, I was only able to make it work if I also added the context configuration annotation:
#ContextConfiguration(classes = MyApplication.class)
I resolved the same issue by excluding the autoconfiguration from my application definition, i.e.
#SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
you can also sue the following annotation:
#RunWith(SpringRunner.class)
#DataJpaTest(excludeAutoConfiguration = {MySqlConfiguration.class, ...})
public class TheClassYouAreUnitTesting {
}
You can just disable it in your test yaml file:
flyway.enabled: false

How to get spring context into testcases

I am using maven project, with spring jpa.
how to test DAO methods in test cases.
And how to get spring context into the test cases
Thanks in advance.
You can use the SpringJUnit4ClassRunner JUnit runner to setup spring in JUnit tests.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/applicationContext-1.xml", "/test-config.xml"})
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class MyTest {
#Autowired
private MySpringBean bean;
}
With the DependencyInjectionTestExecutionListener you can inject spring beans in your test classes.
Have a look at the very extensive Spring Testing documentation.
Take help from below code to inject application context
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfig.clas)
public class ControllerIntegrationTests {
#Autowired
private ApplicationContext applicationContext;
}
If you are using Java based configuration then take help from the above code, if xml is being used as configuring app then replace classes with locations example as below
#ContextConfiguration(classes = TestConfig.class)
or
#ContextConfiguration(locations = "/test-context.xml")

Resources