How to start server once before and stop after all tests? - spring-boot

I want to start a server once before all tests and then shutdown the server after all tests have executed.
In Spring Boot 1.3, I could create a #Component with #PostConstruct to start a server once before tests were executed and then #PreDestroy to stop the server after all tests executed.
After upgrading to Spring Boot 1.5, #PostConstruct is called before every #Test method. #PreDestroy is called for every #Test but only after all tests have executed!
What changed and/or how should I be doing it now?

Similar question with answer - https://stackoverflow.com/questions/42839765/can-you-get-spring-boot-junit-tests-to-use-the-same-server
Apparently, I was being smart while upgrading and changed my WebEnvironment to use RANDOM_PORTs. This causes the Context Caching to be unique for each test class which in turn causes the #Component to be recreated each test.
Thanks

Related

#SpringBootTest loads unrequired Bean when making IT

I'm making some Integration Tests for my app and I'm encountering this problem I can't see how to solve.
I'm using Spring Boot 2.4.13 + Spring Data Neo4J 6.1.9
FYI, I deleted the Application default test that comes bundled when you create a project through Spring Initializr, and under /src/test/resources I have a .yml file named application.yml
My IT class looks like this:
#SpringBootTest
public class ClientIT {
#Autowired
private ClientServiceImpl service;
#Autowired
private ClientRepository repository;
#Test
void someTest() {
//Given
//When
//Then
}
}
But when I run this test I get the following Exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
And this is the cause:
Caused by: java.lang.IllegalStateException: The provided database selection provider differs from the ReactiveNeo4jClient's one.
The thing is I don't use SDN's Reactive features at all in my project. I don't even understand why Spring tries to load it. I've created an Issue under the Spring Data Neo4j GitHub repository (https://github.com/spring-projects/spring-data-neo4j/issues/2488) but they could only tell me that ReactiveNeo4jDataAutoConfiguration gets automatically included if there's a Driver or Flux class in the classpath which I don't have.
I've been debugging the Spring internals while booting up the Application after JUnit Jupiter methods to no success.
What I could see is that at some point after JUnit Jupiter tests preparation/initialization, "reactiveNeo4jTemplate" gets injected into DefaultListableBeanFactory's beanDefinitionNames variable.
I've tried many combinations of different annotations intended to be used when making Integration Tests but the one time it worked was after I explicitly excluded ReactiveNeo4jDataAutoConfiguration class through
#EnableAutoConfiguration(exclude=ReactiveNeo4jDataAutoConfiguration.class)
What I've always seen in some blogposts is that by using #SpringBootTest I shouldn't worry about this kind of problem but it looks like I need to add that annotation every time I want to make a new IT test.
My Integration Tests basically consist of bootstrapping the application + web server (tomcat) along with an embedded Neo4J instance and after that, making requests to check everything works as it should. Do I really need to worry about all of this just to make these simple tests?
Thank you
References:
How do I set up a Spring Data Neo4j integration test with JUnit 5 (in Kotlin)?
SprintBootTest - create only necessary beans
Answering my own question after finding what is causing this error:
In the linked Github Issue, one of the developers says having Flux.class in the classpath forces SDN to instantiate Neo4jReactiveDataAutoConfiguration which is what is causing the other reactive beans to instantiate.
Apparently, neo4j-harness brings io.projectreactor (where Flux.class belongs) as an indirect dependency through neo4j-fabric which is the root of our problems.
The Spring Data Neo4j will be fixing this issue in a patch later this week.

SpringBoot Test - possible to run tests against the default application context?

Execution of the JUnit test of a Spring Boot application causes a testing context of the application to be started whenever the test is invoked. Is there a way to run this test against a spring boot application that has already started without having to spin up a second application context for the test? For example, can the testing framework be instructed to use an existing application context that has already been launched?
#SpringBootTest
#RunWith(SpringRunner.class)
public class MyAppTests {
#Autowired
public SomeService someService;
#Test
public void testInjection() throws AssertionError {
Assert.assertTrue(someService != null);
}
}
There is No way to run tests just using an already started application context, meanwhile without launching a second testing application, if on the premise that you describe.
It means JUnit test of a Spring Boot application is a kind of whitebox testing, the test case will only runs in the environment which is started by itself. The test case has nothing to do with other already running application context.
However, if you really want to run tests against a spring boot application (just like a running test environment) that has already started, maybe you could try some other blackbox testing, for example, API testing or GUI testing. But it will not allow you test SomeService class directly.
Update you test class as below and it should fix your problem.
#SpringBootTest
#RunWith(SpringRunner.class)
#SpringApplicationConfiguration(classes = YourApplication.class)
#ActiveProfiles(Constants.SPRING_PROFILE_DEVELOPMENT)
public class MyAppTests {

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

How to set response date format in rest assured mock mvc while testing spring could contract for a web service?

I am using tests generated by spring cloud contracts to test web service response.
The service used to return date as timestamp, now with the updated Spring version (2.0.5) dates are returned in the "2018-11-30T21:16:18.220+0000" format. The contract tests are still passing without any change. I learned that this is because Spring could contract uses RestAssuredMockMvc which is unaware of springs application configs. How can I change the config in the contracts to make sure that contracts always check for the date in same format as that are correctly returned by the service?
For Spring Boot application, simple way to execute RestAssured against spring application setup is:
#RunWith(SpringRunner.class)
#WebMvcTest
// or #SpringBootTest
public abstract class BaseContractTest {
#Autowired
protected MockMvc mockMvc;
#Before
public void setup() {
RestAssuredMockMvc.mockMvc(mockMvc);
}
}
Version with #WebTestClient runs faster but needs mocking services, version with #SpringBootTest runs slower but utilize whole application.
Proposed in previous answer RestAssuredMockMvc.webAppContextSetup() is very similar to version with #SpringBootTest. The second proposition, RestAssuredMockMvc.standaloneSetup(), requires a complicated configuration, different than Spring application configuration.
For that reason RestAssuredMockMvc.standaloneSetup() is error prone and worse than #WebMvcTest.
RestAssuredMockMvc.webAppContextSetup() is OK
Try this.
Setup object mapper with RestAssuredMockMvc.standaloneSetup
RestAssuredMockMvc.standaloneSetup(
MockMvcBuilders
.standaloneSetup(yourcontroller).setMessageConverters(mappingJackson2HttpMessageConverter)
);
Either add the missing configuration to the mockmvc rest assured setup or use explicit mode of tests generation and setup a real spring boot context

Spring JUnit4 Test Hangs after few runs

I am using Spring with DbUnit to test my DAOs. I have an TestExecutionListener to add/delete data from DB before and after each test class. Here is my abstract test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:spring/test-dao.xml"})
#TestExecutionListeners(
{ DependencyInjectionTestExecutionListener.class,CleanInsertTestExecutionListener.class}
)
#DataSetLocation("classpath:data/test-dao-dataset.xml")
public abstract class AbstractDaoTests {
I have grouped my tests into a Suite and when I execute the Suite, only the first few tests run and then tests hangs indefinitely. Not sure what would be the cause of it. I don't see any exceptions either.
Any idea or pointers on what could be causing it would be very helpful.
I am able to run the individual tests but the issue happens when I try to run them in a suite.
Also, I am using Apache Commons pool BasicDataSource to access the DB.
Thanks,
Javid
Found the issue.
I was not closing the DBUnit Connection object in my TestExecutionListeners in the beforeTestClass & afterTestClass methods.
Closing the connection fixed the issue.
Thanks,
Javid

Resources