Unable to post to Spring Data Rest RepositoryRestResource in integration tests - spring-boot

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.

Related

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

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

Start services manually when doing a spring boot test

So I have a test class annotated with #SpringBootTest
#SpringBootTest
#Slf4j
public class IntegrationTests {}
This code automatically starts two of classes in my application annotated with #service.
In my integration test I’m testing the spring scheduler to works as expected and the tests passes.
Now I want to write another test that only test one of the two services annotated with #service. The second service I want to enable and disable myself. This is because one of two services uses the springboot #scheduled annotation, which results in unpredictable logic.
So is there a way I can start a #SpringBootTest with the possibility to choose the services I need?
Thanks in advance!
Have you tried adding the test classes in #SpringBootTest? like so:
#SpringBootTest(classes = YourTestClass.class)

how to run springboot test without run tomcat?

I am developing a spring boot application and write some junit test.
But I find when I run any tests, tomcat is also started up, It makes those tests very slow and waste many times.
When I develop a SpringMvc application, junit test can run without start tomcat, It saves many times.
So, I want to ask it there anyway to run springboot test with out start tomcat?
Running a test with #SpringBootTest does not start an embedded server by default.
By default, it runs in the MOCK environment.
By default, #SpringBootTest will not start a server. You can use the
webEnvironment attribute of #SpringBootTest to further refine how your
tests run:
MOCK(Default) : Loads a web ApplicationContext and provides a mock web
environment. Embedded servers are not started when using this
annotation. If a web environment is not available on your classpath,
this mode transparently falls back to creating a regular non-web
ApplicationContext. It can be used in conjunction with
#AutoConfigureMockMvc or #AutoConfigureWebTestClient for mock-based
testing of your web application.
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
I guess what you wanted to achieve could be achieved by Slice Test concept. In general, you don't need a full-fledged mock environment or environment with an embedded server with all the configured beans in the spring container when you are performing unit tests.
For e.g. you have to unit test your Controller then you have #WebMvcTest annotation in place that will configure only web related beans and ignore the rest of the beans.
To test whether Spring MVC controllers are working as expected, use
the #WebMvcTest annotation. #WebMvcTest auto-configures the Spring MVC
infrastructure and limits scanned beans to #Controller,
#ControllerAdvice, #JsonComponent, Converter, GenericConverter,
Filter, WebMvcConfigurer, and HandlerMethodArgumentResolver. Regular
#Component beans are not scanned when using this annotation.
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests
Similarly, for the database layer, there is #DataJpaTest
Documentation link: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test
Long story short: when you intend to do unit testing with Spring framework, slice test is the one you should use in most of the cases.
If you are placing the following annotations, this will start the embedded container...
#RunWith(SpringRunner.class)
#SpringBootTest
Because, if you see the SpringBootTestContextBootstrapper.class class , this has been invoked the container which is invoked by #BootstrapWith(SpringBootTestContextBootstrapper.class) when we specify #SpringBootTest
You can remove those and can do as follows:
import org.junit.Test;
public class HellotomApplicationTests {
#Test
public void contextLoads() {
}
}
R-Click and RunAs Junit
O/P

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

Resources