SpringBoot #IntegrationTest annotation for testing - spring-boot

I am very new to SpringBoot. I need to understand how to write an integration test using SpringBoot. I have seen some examples on the Internet which use the #IntegrationTest annotation whereas some other examples which use the #SpringBootTest annotation.
I am just wondering what is the difference between the two?
Which is the best way of writing an integration test in Spring boot?

The IntegrationTest was deprecated sine spring boot 1.4, so the suggestion is using SpringBootTest after 1.4
Deprecated as of 1.4 in favor of org.springframework.boot.test.context.SpringBootTest with webEnvironment=RANDOM_PORT or webEnvironment=DEFINED_PORT.

Basic template for writing the integration tests in springboot.
the sql group is additional annotation. When ever you want to execute the particular sql queries before and after method run so u can use #SqlGroup annotation.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = MainApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#SqlGroup({
#Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD,
scripts = "classpath:beforeTestRun.sql"),
#Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD,
scripts = "classpath:afterTestRun.sql")})
public class CustomerControllerIntTest {}

Related

Spring Boot 2.1 - #WebMvcTest without Spring Security Auto-Configuration

Before migrating to Spring Boot 2.1, we had a couple of controller tests in our services utilizing #WebMvcTest in combination with #AutoConfigureMockMvc:
#WebMvcTest(SomeController.class)
#AutoConfigureMockMvc(secure = false)
public class SomeControllerTests { ... }
This had the effect that the Spring Security configuration was disabled and you could run MVC tests without mocking OAuth/JWT.
In Spring Boot 2.1, the secured attribute is deprecated and the release notes mention that
[...] #WebMvcTest looks for a WebSecurityConfigurer bean [...].
In order to avoid the deprecated secured attribute and loading of our WebSecurityConfigurer we rewrote our tests to:
#WebMvcTest(
value = SomeController.class,
excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = WebSecurityConfigurer.class),
excludeAutoConfiguration = MockMvcSecurityAutoConfiguration.class)
public class SomeControllerTests { ... }
The question is: is there a more compact way in Spring Boot 2.1 to define such tests?
Yes, rather than working around the fact the flag is deprecated, you should embrace the fact that this is going in that direction going forward.
As of Spring Boot 2.1, if you have Spring Security, your tests will be secured using your custom configuration. What is the actual problem with that?
If you don't want to authenticate for certain tests, just use Spring Security's test infrastructure and add #WithMockUser.
Encountered the same scenario and what helped was using the below annotations instead of #WebMvcTest. In this case, #WithMockUser did not help.
#WebAppConfiguration
#Import({MockMvcAutoConfiguration.class})
#EnableConfigurationProperties({ResourceProperties.class, WebMvcProperties.class})
Classes that existed in controllers / value of #WebMvcTest goes into value of #Import annotation.
Source: https://github.com/spring-projects/spring-boot/issues/14227#issuecomment-688824627

Cucumber and Spring boot integration

I have a microservice application developed using spring boot and used cucumber to test. I have a separate project folder "bdd" where I stored all my features files and the step defns and this project is not deployed in the war file.
I have a requirement where I need to hit the DAO class's methods directly for some testing and I found that from BDD folder, I don't have the access to get the instance of the beans from spring boot.
Found some articles as well on how to integrate the cucumber and the spring boot using the #RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) annotations. however It seems not to be working for me.
Does anyone have experience any such requirements or could anyone suggest me on what should be the correct approach.
Thanks.
Edited :
I am trying to use an instance of a bean which was initialized already as part of the spring container. when I tried to #Autowire or #Inject using:here registry is the bean instance I am trying to use.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Component
public class AbstractDefs {
#Autowired
private static ConnectionProviderRegistry registry;
dao = new MyDaoClass(registry);
the variable registry is still null.

How to speed up unit tests with less configuration

The unit test template of jhipster is great, but sometime, especially, during coding, I need to write unit test code and run frequently. But now the unit test will start tomcat container and many other module, which I don't need if I want to test a service function.
Now the test class is like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
#Transactional
public class SomeClassTest {
.....
How can I modify it to only initialize spring container and DB? Thanks.
If you do not need the server, don't make your test an integration test. If you remove #WebAppConfiguration and #IntegrationTest spring boot will start a regular (i.e. non-web context) and will not start Tomcat.
If you need to go even further, you can disable certain features, either via application-test.properties + #ActiveProfiles("test") to disable stuff via config or using the exclude parameter of #SpringBootApplication (or #EnableAutoConfiguration) as Lukas said already.
Take a look at this question How to exclude *AutoConfiguration classes in Spring Boot JUnit tests? and see if this helps you. The idea is to explicitly exclude auto configurations that you don't need in your test, so in your case it would probably be EmbeddedServletContainerAutoConfiguration

Spring-Boot module based integration testing

I have a multi-module Spring-Boot project.
I was wondering how I can set up integration testing just to test Spring Data JPA repositories? The following approach fails with this exception:
HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath.
Since this module does not depend on the web module, there is no web application that can be started.
#RunWith(SpringJUnit4ClassRunner.class)
#IntegrationTest
#SpringApplicationConfiguration(classes = TestConfiguration.class)
class CardInfoRepositoryIT {
#Autowired CardInfoRepository cardInfoRepository;
#Test
void testLoadData() {
assert cardInfoRepository.findAll().size() == 1
}
}
As Marten mentioned, #IntegrationTest should only be used when you need to test against the deployed Spring Boot application (e.g., deployed in an embedded Tomcat, Jetty, or Undertow container). So if your goal is to test your repository layer in isolation, you should not use #IntegrationTest.
On the other hand, if your tests require specific Spring Boot functionality (in contrast to standard Spring Framework functionality, semantics, and defaults), then you will in fact want to annotate your test class with #SpringApplicationConfiguration instead of #ContextConfiguration. The reason is that #SpringApplicationConfiguration preconfigures the SpringApplicationContextLoader which is specific to Spring Boot.
Furthermore, if you want your repository layer integration tests to run faster (i.e., without the full overhead of Spring Boot), you may choose to exclude configuration classes annotated with #EnableAutoConfiguration since that will auto-configure every candidate for auto-configuration found in the classpath. So, for example, if you just want to have Spring Boot auto-configure an embedded database and Spring Data JPA (with Hibernate as the JPA provider) along with entity scanning, you could compose your test configuration something like this:
#Configuration
#EnableJpaRepositories(basePackageClasses = UserRepository.class)
#EntityScan(basePackageClasses = User.class)
#Import({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
public class TestRepositoryConfig {}
And then use that configuration in your test class like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestRepositoryConfig.class)
#Transactional
public class UserRepositoryTests { /* ... */ }
Regards,
Sam
p.s. You might find my answer to the following, related question useful as well: Disable security for unit tests with spring boot
I resolved this by having the following test config class.
#Configuration
#EnableAutoConfiguration
#ComponentScan
#PropertySource("classpath:core.properties")
class TestConfiguration {
}
core.properties is also used by the main application and it contains datasource information. #IntegrationTest annotation can be removed on the test class.
I also added the following to the module as dependencies:
testRuntime 'javax.el:javax.el-api:2.2.4'
testRuntime 'org.glassfish.web:javax.el:2.2.4'

Using Spring #ActiveProfile in integration tests

I am using #Profile Spring annotations to choose between embedded, standalone and container managed data sources. In order to choose 'embedded' my integration tests are annotated to activate the appropriate profile:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={TestConfigWrapper.class})
#ActiveProfiles({"EMBEDDED_DB"})
public class SomeIntegrationTest {
The problem is that I would like to move '#ActiveProfiles' into TestConfigWrapper, but doing this doesn't get picked up and the application context won't load any DataSources.
This means I have to annotate every integration test with an #ActiveProfile which effectively means it becomes integration test boiler-plate and could easily hamper future refactoring.
Is there a way I can do this using java config?
Per comment from Hippooom use an abstract class to configure tests:
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={WebAppInitializer.class})
#ActiveProfiles({Profiles.EMBEDDED_DB})
public abstract class ProfiledIntegrationTest {
}

Resources