TestNG: Use ApplicationContext in multiple Test-Classes - spring

I've written some test-cases inside a single TestNG Test which extends AbstractTestNGSpringContextTests. The ApplicationContext is correctly setup and I can use it inside my test-cases.
The problem is that the setting up of the applicationContext can take some time and I don't want to do this for every test-class I have, as this would take some time which is unnecessary from my point of view.
So my question is: Is it possible to run more than one TestNG test-class using the same Spring ApplicationContext which is setup only once?
Thanks and best regards,
Robert

How about using a #BeforeSuite?

Spring may cache and re-use ApplicationContext when you use similar locations in #ContextConfiguration annotations. See related article from Tomasz Nurkiewicz (#tomasz-nurkiewicz) at http://nurkiewicz.blogspot.com/2010/12/speeding-up-spring-integration-tests.html

Once the TestContext framework loads an ApplicationContext (or WebApplicationContext) for a test, that context will be cached and reused for all subsequent tests that declare the same unique context configuration within the same test suite.
The Spring TestContext framework stores application contexts in a static cache. This means that the context is literally stored in a static variable. In other words, if tests execute in separate processes the static cache will be cleared between each test execution, and this will effectively disable the caching mechanism.
To benefit from the caching mechanism, all tests must run within the same process or test suite. This can be achieved by executing all tests as a group within an IDE. Similarly, when executing tests with a build framework such as Ant, Maven, or Gradle it is important to make sure that the build framework does not fork between tests. For example, if the forkMode for the Maven Surefire plug-in is set to always or pertest, the TestContext framework will not be able to cache application contexts between test classes and the build process will run significantly slower as a result.

Related

How to create spring boot test suite

Say I have 10 spring boot test class (annotated with #RunWith(SpringRunner.class) and #SpringBootTest)
Each test needs to launch spring container for like 10 seconds, although the container might do the same init.
So I may need 100 seconds for "mvn test".
Is there a way I can group my 10 test class into 1 suite, and let the container only start once.
So I can:
Only run the suite for "mvn test". (with proper naming for individual test class)
Optionally run individual test in IDE.
Spring uses Cache Management to cache the Application Context between tests:
By default, once loaded, the configured ApplicationContext is reused for each test. Thus, the setup cost is incurred only once per test suite, and subsequent test execution is much faster. In this context, the term “test suite” means all tests run in the same JVM — for example, all tests run from an Ant, Maven, or Gradle build for a given project or module. In the unlikely case that a test corrupts the application context and requires reloading (for example, by modifying a bean definition or the state of an application object) the TestContext framework can be configured to reload the configuration and rebuild the application context before executing the next test. (https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/testing.html#integration-testing)
So this mechanism tries to execute your integration tests on an already running Application Context if possible. As you see multiple Application Context launches, this indicates your tests somehow use a different setup e.g. different profiles active, test properties, MockBeans etc.
The Spring documentation provides an overview on which indicators it puts an Application Context in its cache: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/testing.html#testcontext-ctx-management-caching
If you e.g. don't change any test property for your integration tests, Spring can run all of them on only one Application Context and be extremely efficient.
Another indicator for your current behaviour might be the use of #DirtiesContext which leads to a fresh Application Context after your test executes.

How does Spring Boot Test keep the context across multiple test suites?

I was reading through the guide for using Spring Boot Test and there was a paragraph that got me confused.
“As our profiles get richer, it's tempting to swap every now and then in our integration tests. There are convenient tools to do so, like #ActiveProfiles. However, every time we pull a test with a new profile, a new ApplicationContext gets created.”
https://www.baeldung.com/spring-tests
So it assumes that if all tests are run under the same profile, there is only one ApplicationContext created — but how is it possible? I thought that all the objects are recreated for each test suite anyway. Am I missing something?
The official reference says that it's cached.
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/testing.html#testing-ctx-management
But how does it get loaded into the JUnit runner or Spock one across multiple test suites?
What was missing in my understanding is the fact that all the test suites are run as a part of a single program, so it's easy to cache any objects that are required by all of them, including Spring context.

Forked execution of SpringBootTest's with maven failsafe plugin - does it work out of the box?

Consider you have a Spring-Boot Application and within this application also a bunch of Integration-Tests, which are annotated with #SpringBootTest and run with the SpringRunner class.
They are invoked by the maven failsafe plugin, which by default does not parallelise tests in any way. The tests all run fine without any issues.
What changes if you use failsafe's feature of forkCount - can you expect the test execution to work out of the box? Do you need to adjust some code? What do you need to look out for that could potentially not allow these integration tests to run in a forked, "parallel" environment via this plugin?
From my understanding, the failsafe plugin will create forkCount-many JVMs and in each some of the integration tests are executed. That sounds like there is nothing to do, you don't need to make anything threadsafe, you don't need to make Singleton-beans into ThreadScoped beans or anything - as the process of having multiple JVM's should already create multiple of these beans.
Sorry if the question appears weird, I tried researching this question but I could not find an answer.
From Maven doc:
The parameter forkCount defines the maximum number of JVM processes
This means that the tests will run in it's own process and therefore you will have separate Spring Boot instances. So you really don't have to care about thread safety.
But you have to care about memory consumption.

How to ignore a java file when maven install

I have a #Service class where i'm caching some table data. I don't want those queries to run while building mvn install. Is there a way to ignore the file while building and it only execute when i start the server ?
It's a spring-boot application.
Here is background of my issue. I have initialized the spring boot app from http://start.spring.io/ site, which actually adds dummy application test file with SpringBootTest annotation and default contextLoads() with Test annotation, with an intention to initialize and execute all test cases, which needs to initialize and execute all code base. In my opinion this is not required, as we can have respective Test classes per controller/manager, which will give more controlled environment to hook up your Test setups and executions.
I have removed the default application Test file and included respective test classes for code coverage and quality. This way my beans are not executed at server startup time rather build time.

Access Spring beans from a Junit Suite

I want to accomplish this - Run a background process (a Solr instance actually) that all the tests in my JUnit Suite will use.
To do this - Created a JUnit class annotated with #RunWith(Suites.class). And added a ClassRule on the Suite to start the server and stop it. Individual tests in the suite were annotated with #SpringApplicationConfiguration and #RunWith(SpringJunit4ClassRunner.class). And I also require access to some of the Beans in the Suite itself (like a spring managed settings bean). What's the best way to do this. What I tried.
Annotated individual tests with #SpringApplicationConfiguration
Had the Suite create an ApplicationContext via
SpringApplication.run and access any bean that it wants (a spring
managed Settings bean for example and use it one of ClassRules of
this Suite).
What I observed is that the ApplicationContext context gets created everytime, One for the Suite because I called SpringApplication.run and one for every test. I obviously want to avoid this and caching of the ApplicationContext between test runs also does not seem to work in this case.
So what are the best practices to handle this case.
Any suggestions/recommendations will be highly appreciated.
This is a long forgotten question, but it shown up on my google search, so I am assuming it still somehow relevant :)
I was going down on the same path but I hit so many road blocks that I decided to change my approach:
Create a JUnit runner as described here.
Change #1 to inherit SpringJUnit4ClassRunner here is an example.
Finally, annotate your Test classes with #RunWith(MyCustomRunner.class)
There you go. You can add whatever logic you need inside your runner.

Resources