start the Spring Boot application once, before Cucumber tests run - spring-boot

I am writing some BDD tests using Cucumber for my Spring Boot application (v2.2.1), and it works OK.
However, I am facing some performance issue, because the application gets started/stopped for every scenario in the feature file : I am using in-memory DB with Liquibase, so for each scenario, this gets executed (takes a few seconds).
Sure, it's currently guaranteed that my scenarios are very well isolated.. Maybe in some cases I will want this behaviour, but right now, most of my feature files would benefit from a one time set up : since each scenario sets up different records (with no overlap) it needs in the in-memory DB, I could theoretically executed my scenarios in parallel on a single Spring Boot application running.
I saw https://blog.codecentric.de/en/2017/02/integration-testing-strategies-spring-boot-microservices-part-2/ , but it requires to have built the application first, then start it from the jar.
Isn't there a way to do the same, but with the application started once from the Cucumber runner ? any example somewhere ?

Thanks to #mpkorstanje link, I was able to find the issue : while trying to replicate the suggestion in my project, I discovered that one of the config that was scanned had a #DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) annotation.. So that was the issue. Now I need to look at a workaround like what is suggested here : #DirtiesContext tears context down after every cucumber test scenario, not class

Related

Reusing expensive beans in Spring Boot Tests

I am trying to improve performance of medium tests in Spring Boot.
I am using the Spring Boot - testcontainers library.
For an individual test this works really well, with a few annotations I can get access to kafka, zookeeper, and schema-registry. These are full services so it takes a few seconds to start everything up, all together setup takes about 40 seconds. The test accurately recreates a realistic deployment, it's beautifully simple.
This would be fine if it just happened once but it happens every time a Spring Context is created. That means every test that uses #MockBean incurs that 40 second cost.
I've tried refactoring into a single TestConfiguration class and referencing that. I've looked into using ContextHierarchy but I think that means I'll lose all of the Spring Boot niceties and I'll need to recreate the context (which means it won't look exactly like the context created by the production app).
Is there a better way to do this?
Spring framework already took care of this scenario.
There is a concept of caching the application context for test class/classes.
See the documentation.
Few lines from the documentation:
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 run in separate processes,
the static cache is cleared between each test execution, which
effectively disables the caching mechanism.
So essentially you need to structure your code or context configuration in such a way that you use cached context in your desired test cases.
But use this capability wisely, if not thought through properly this could lead to undesired side-effects

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.

Starting embedded servers before context loads in Spring Boot for testing

I am working on a sample application right now using Spring Boot, Spring Data JPA, and Spring Data Elasticsearch. I want to be able to run the unit tests as part of a pipeline build, but they require Elasticsearch to be running to work as the service makes calls to said ES server. SQL works fine because I am using an in-memory H2 instance.
I have implemented some code to attempt to launch ES as an "embedded" server. The embedded server works just fine, but it seems like, at least from what I can tell, it is started AFTER the context loads. Most importantly after the ElasticSearchConfiguration does it's thing.
I think I need refactor the code out of AbstractElasticsearchTest into a separate class that can run prior to ElasticSearchConfiguration generates the client/template, but I am not sure how to do it, nor how to Google said process.
Is there some mechanism in Spring Boot that could be used to start the embedded servers prior to running any of the configurations? Or is there some way I could enhance ElasticSearchConfiguration to do it prior to creating the client/template, but only when running the unit tests?
Edit:
So, just to be a little more specific...what I am looking for is a means/way to either run ES 5 in "embedded" mode OR how to mock up the Spring Data ES code enough so that it works for the CI server. The code linked above currently is mixing unit tests with integration tests, I know, as it's currently making calls to a physical ES server. That's what I am trying to correct: I should be able to stub/mock enough of the underlying Spring Data code to make the unit test think it's talking to the real-deal. I can then change the tests that determine if the documents made it to ES and test things like type-ahead searches to be integration tests instead so they do not run when CI or Sonar runs.
Ok, so for those that might come back here in the future, this commit shows the changes I made to get ES to run as "embedded".
The nuts-and-bolts of it was to start the node as "local" then physically return node.client(). Then in the Spring Bean method that gets the client, check if you have "embedded" turned on, if so start the node and return it's Client (the local one), if not just build the client just as normal.

Can you get Spring Boot JUnit tests to use the same server?

I have some Spring Boot JUnit tests that require a somewhat lengthy server start up (I'm loading a complex domain in JPA). I've put them into a test suite, but each test kicks off a new server start up.
Is it possible to set them up in such a way that the server is only started once and each test is loaded onto it and run as if the server were started by the test itself?
Okay, so the solution here is actually built in to Spring testing. That is, it caches ApplicationContexts for tests, as described here, as long as the various things like properties are the same.
Ironically, I screwed this up by trying to speed up the tests by using test properties to limit what was loaded.

Verify Spring Configuration without full start up

I have a large spring project, using xml configuration. I'm looking for a quick way to verify changes to the xml configuration.
I can load the whole project locally - the problem is this takes more than 5 minutes, loads a huge amount of data.
My XML editor catches XML formatting errors.
I'm looking for something intermediate - to catch obvious problems like references to beans that aren't defined, or calling constructors with the wrong arguments. Is there a quick way to do this, without having to actually invoke all the constructors and bring up the whole environment?
I'm building with Maven and editing with Eclipse, although my question isn't specific to either.
Since you already use Eclipse, you could try Spring Tool Suite (comes either standalone or as an add-on). It's essentially Eclipse with extra Spring-specific features, like Beans Validator. I'm not sure how thorough the validation is, but it should catch most configuration problems.
It's maintained by SpringSource so its integration with Spring "just works" and it's guaranteed not be more or less in sync with Spring Framework's release cycle.
Beanoh :
http://beanoh.org/overview.html#Verify
this project does exactly what I'm looking for. Verify obvious problems with spring config, but without the overhead of initializing everything.
You can use a Spring testing support to integration test your Spring configuration. However if the loading of the context is taking 5 mins, then the tests will also take the same amount of time. Spring does cache the context so if you have multiple tests using the same set of Spring contexts, then once cached the tests should be very quick.
I can suggest a few ways to more efficiently test your configuration:
Organize your project in modules, with each module being responsible for its own Spring configuration - this way, each module can be independently developed and tested.
If you have a modular structure, the testing can be more localized by mocking out the dependent modules, again this is for speed.

Resources