I have a project with Spring which has integration tests with JUnit. When I run the tests, I can see the difference between execution time of the tests and real time. Real time (the time between I press "run test" and finished tests) is something like 1.5 times greater than "junit time".
Why does this difference exist? Is it induced by Spring context startup and shutdown?
Execution time is just the amount of time for the test case. The real time is everything else. Spring context startup and shutdown. And any before and/or after methods.
Related
I am working on a spring-boot service which is taking around 56 sec to start.
I would like to know if there is a possibility to reduce the application start-up time by configuring multiple threads for start-up process.
Thanks and regards,
Suraj Jannu
By default, no. Spring Inits all of the beans on startup, to fail-fast, and not let the app be up (but not running). If you still would take the chance of runtime failures due to Init error of some beans later, only when needed, you can use Lazy loading: https://howtodoinjava.com/spring5/core/spring-bean-eager-vs-lazy-init
Our project has over 500 test suites. It takes up to 30 mins to run and I found a huge amount of time spending is on Liquibase when initializing Spring context for test suite.
Would like to know if there are any good approach to accelerate the process? E.g. Run Liquibase one time and do file copy (h2 database) to reset database for each 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.
All my tests share the same Spring configuration. It works effectively because context is started once and reused. Whole test suite completes in short time.
The problem is when Spring configuration is broken. In such case first test fails with
IllegalStateException: Failed to load ApplicationContext
and each next test the same. It last long, because for each test context is started and failed.
Usually I am satisfied when testing process is continued after failure. But in this case I prefer to stop testing process - if context is not started once, it will never start successfully.
Is is possible to break test process in such case in JUnit 4/5?
JUnit 4 has option to request stop tests, see https://stackoverflow.com/a/31397394/2365727
But using it is a bit difficult.
JUnit 5 seems do not have equivalent
While developing a Grails 1.0.5 app I'm appalled at how slow the grails test-app command is. Even though the actual tests take just ~10 seconds, the whole execution adds up to
real 1m26.953s
user 0m53.955s
sys 0m1.860s
This includes grails bootstrapping, loading plugins, compiling all the code, etc.
Any hints on how to speed up the grails test-app execution would be greatly appreciated.
You can use interactive mode to speed up your test runs.
Just run
grails interactive
Then type
test-app
The first time will be the same as usual but each time after that will be dramatically faster. There are currently some issues with interactive mode (like running out of memory after a few runs) but I still find it worth it.
There aren't any hard and fast rules for speeding it up, and the performance issues that you're seeing might be specific to your app.
If your bootstrapping is taking ~75 seconds, that sounds pretty long. I'd take a close look at whatever you have in your Bootstrap.groovy file to see if that can be slimmed down.
Do you have any extra plugins that you might not need (or that could have a major performance penalty)?
This might not be a possibility for you right now, but the speed improvements in grails 1.1.1/groovy 1.6.3 over grails 1.0.5/groovy 1.5.7 are fairly significant.
Another thing that really helps me when testing, is to specify only integration tests or only unit tests if I'm workiing on one or the other:
grails test-app -unit
grails test-app -integration
You can also specify a particular test class (without the "Tests" prefix), to run a single test which can really help with TDD (ex for "MyServiceTests" integration):
grails test-app -integration MyService
In grails 1.1.1, bootstrapping with 5 plugins and ~40 domain classes takes me less than 20 seconds.
If you're still using Groovy 1.5.x you could probably of shave a few seconds by upgrading to Groovy 1.6
Please see my answer here. A plugin relying on a poorly defined maven artifact can cause grails to go and look every time for a newer version.
Grails very slow to resolve certain dependencies
You can choose to run unit and integration tests in parallel as well - see this article
Increasing the java memory/JVM options can definitely speed things up. The amount of memory you can give depends on your equipment.
If you are running grails from the command line, set the GRAILS_OPTS environment variable. Add something like this to ~/.bash_profile
export GRAILS_OPTS="-Xms3000M -Xmx3000M -XX:PermSize=256m -XX:MaxPermSize=512m"
If you use GGTS(Eclipse) you'll need to add this to the VM arguments of the run configuration.
There are also a few JVM settings that can be modified to increase the speed:
-XX:+UseCodeCacheFlushing
-XX:MaxInlineLevel=15
-noverify (turns off class validation)
grails now comes with http://grails.org/plugin/testing installed. this mocks the domain stuff, so you can do some testing of domain classes as unit tests. they run pretty fast.