Springboot 2 controller integration test transactional (lazy-loading) session issue - spring-boot

Issue
I had an Hibernate lazy loading issue when using Postman to send a reqeust derectly to a Springboot service endpoint, which is bacause I have a collection marked as FetchType.Lazy in an entity and this issue can be resolved by marking the service method as #Transactional.
However, if I remove that #Transactional, my Springboot controller test still passed without any Hibernate lazy loading issue.
This looks like all of the Springboot controller integration tests are always transactional. But I couldn't find any official document about it. So, my question is, is it correct?
For my integration test, I use the annotations below
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ApiApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#TestPropertySource(locations = "classpath:application.properties")

As #Josef said in comment above, my issue here is about default Spring jpa config spring.jpa.oepn-in-view=true. For more details, please read:
What is this spring.jpa.open-in-view=true property in Spring Boot?
https://www.baeldung.com/spring-open-session-in-view

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.

Unable to post to Spring Data Rest RepositoryRestResource in integration tests

It doesn't appear in the integration tests that the resource links are exposed for my repositories. They appear fine when the application is running but during the test a POST to, what should be a valid uri, gives a 404 with the message
The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
configuration
#RunWith(SpringRunner.class)
#ActiveProfiles("test")
#DirtiesContext
#SpringBootTest(
classes = {ServletWebServerFactoryAutoConfiguration.class, AnsApplication.class, PostgreSQLConfiguration.class},
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT
)
#DataJpaTest
#EnableJpaRepositories(basePackages = {"xxx.xxx.xxx"})
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
Note this configuration works fine for integration tests that save and retrieve entities using an injected repository, posting against the repository is the problem.
As it turns out, there is some interaction with the #DataJpaTest annotation that also required adding ServletWebServerFactoryAutoConfiguration.class to the #SpringBootTest list. This created a container which did not have my endpoints registered.
Removing both #DataJpaTest and ServletWebServerFactoryAutoConfiguration.class from the configuration list allowed my integration tests using TestRestTemplate to work. For JPA specific tests I will add them back.

Disable autoconfiguration for Spring Cloud Config in a test class of a Spring Boot application

I have a test class annotated with #DataJpaTest which autoconfigures Cloud Config.
I want to stop that for that one test class. I cannot use the spring.cloud.config.enabled=false application property, because that would disable it for all tests.
Any suggestions?
#DataJpaTest annotation has other attributes. I tried the following to specifically disable the Spring Cloud Config and it worked for me locally:
#DataJpaTest(properties = {"spring.cloud.config.enabled=false"})
#DataJpaTest takes a excludeAutoConfiguration argument. You can specify all the AutoConfig's which you want to exclude.
#DataJpaTest(excludeAutoConfiguration = {AbcCloudAutoConfig.class, DefCloudAutoConfig.class})
replace AbcCloudAutoConfig, DefCloudAutoConfig with the classes you want to exclude

WebApplicationContext is always null in a spring boot test

My test class looks like this
#SpringBootTest(webEnvironment=WebEnvironment.MOCK)
public class sampleClassTest{
#Autowired
private WebApplicationContext wac;
}
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
In the setup method, wac is always null. From spring boot documentation, #SpringBootTest(webEnvironment=WebEnvironment.MOCK) always created a mock WebapplicaitonContext.
So I would expect it get autowired in the code above which doesn't happen.
Can someone tell me how to go about creating a webapplicationContext in this case so that it's not null like in my case ?
UPDATE
I am running spring boot tests invoking them from a class with springboot annotation.
Both test (springboottest) and calling class (springboot) application are in the same spring boot project under src/main/java.
I have nothing under src/main/test. I have done in this way because if classes from src/main/java want to call a test class then, it isn't really a test class.
Now, the problem is that I can't use runWith(SpringRunner.class) in springbootTest class. If I did that to get a mock webApplicationContext then, it gives me this error:
javax.management.InstanceAlreadyExistsException: org.springframework.boot:type=Admin,name=SpringApplication
I am not sure how to do about this.
To use #SpringBootTest you need to use Spring Framework's test runner. Annotate your test class with #RunWith(SpringRunner.class).
If someone is struggling with this issue in 2022 - please keep my defined precondions in mind. If you are using #SpringBootTest with defined port and constructor auto-wiring of the test class, the application context might be null.
It seems that the constructor dependency injection is eager and the cache aware context delegate of Spring is searching for a web application context which is no available yet. If you use field auto-wiring your test might run in a deterministic manner.
Whoever is facing this issue, make sure your spring boot starter parent version is compatible with spring cloud version in pom.xml
I was facing same issue, i resolved it by doing same.

Resources