Spring Boot test profile - java

I want to run UAT tests using Spring Boot. I want to run them on multiple configurations in parallel.
I will start by saying that I'm not sure if it's a good practice to run mvn test on the same project in parallel. But let's pretend I'll do that.
The suggestions I find on the internet for testing different configurations are:
either have different profiles and put this in the base application.yml : spring.profiles.active=profilex
either use environment variables instead of profiles
Both will not work with running in parallel: application.yml can't have different values at the same time, the same with environment variables.
Is there any kind of way to specify the profile with command line arguments, something like mvn test -DprofilesActive=profilex ? Or any other way?
EDIT - concrete example:
I have a REST service deployed on 2 servers.
I have a separate project for testing the REST service using Cucumber (so JUnit tests). This is a Spring Boot project. It takes the URL of the server where the REST service is deployed from application.yml (at the moment).
I want to run this test project in parallel twice , for each deployed REST service, meaning with the 1st URL and the 2nd URL.
I run it using mvn test.

Related

What is the difference between Profiles via Spring or via a build tool like Maven/Gradle

We are currently developing a Spring Boot based application and we have a QA and a Prod environment to deploy.
I suggested that having different app properties file for different environments and then using -Dspring.profiles.active in a Docker compose file would be a good solution for profiling.
But, my colleague says that having a build tool based profiling would be a better idea. Something like this - https://mkyong.com/maven/maven-profiles-example/
Please help me understand the advantages and disadvantages between these two ways as I am not finding sufficient reading materials online.
With Mvn/Gradle profiles, the profile is selected at build time. So you will need to rebuild your project for Prod after it's accepted on QA.
With Spring, the profile is selected at runtime. You can deploy the same WAR file or Docker image on QA or on Prod, but you only need to change the runtime profile, e.g. via the command line -Dspring.profiles.active=... or via an environment variable SPRING_PROFILES_ACTIVE=..., and Spring will select either application-qa.properties or application-prod.properties during startup.
Having the same Docker image on Prod or QA is definitely better, I think. The downside of using Spring profiles that you include the property sets for both QA and Prod inside the image, and when you want to change either one, you will have to rebuild the whole Docker image.
A third option is not to use profiles at all, but externalize all properties that are not the same for QA or Prod. For example, set spring.datasource.url, username, password, etc, via a deploy descriptor rather than include it in your docker image. This way, you can reuse the same Docker image for any environment, and reconfigure it on the fly. Additionally, you can keep production passwords secret from developers if you want.
What #JArgente suggest goes even a step further: read the properties from an external service at startup time. But that may be overkill, if you can do it via Kubernetes environment variables.
To compare Spring and Mvn/Gradle is to compare 2 tools designed for different things.
Both however, allow you to feed configuration through different mechanics. Spring profiles are intended to be used for deploying applications in different environments, so in terms of use-case and intended use, what you described fits in to this.
(Ref: https://docs.spring.io/spring-boot/docs/1.2.0.M1/reference/html/boot-features-profiles.html )
Here's a couple of advantages of using Spring profiles over a build tool's config
I thought of:
Can switch profile without rebuilding the application
Can debug the application itself rather than looking at the build config, which should be easier
I think the best approach to change configuration based on environment is to use an external config server where the service will connect at startup and fetch the configuration that applies to the environment where the app is deploying.
For example, you can use spring-cloud-config server and create different configuration files for each environment and when the service deploys, use spring profiles to know what is the environment in which the application is being deployed and get the correct configuration:
https://cloud.spring.io/spring-cloud-config/reference/html/

Spring Boot IT test after Deploy

I have Spring Boot Integration tests (IT) that connect to a real DB or to a real 3rd parties. I use them during development but I find them quite usefull to check the real behaviour of the application therefore I would like to run them during CI process. The goal is to run them on the environment on which the application is deployed and not on CI machine where Jenkins is running. Is there a way how to achieve this? I know I can use for example SOAP UI maven plugin and execute tests against REST endpoints, but I would prefer to use Spring Boot IT tests already written.
Many thanks
Running tests against your production database is a really bad idea. Please please please reconsider. It is better to have your test database updated to be more like production than to run your tests on production data.
That being said, you can point your database configuration to your production machine via the application.properties file (mongo example):
spring.data.mongodb.uri=mongodb://user:pass#production.myhost.com:27017/mydb
I'm guessing that it defaults to localhost:27017. In your test/resources folder you can setup a differing application.properties. Check out the spring-boot externalized properties details.

Is it possible to start up an external spring-boot application programmatically

I have created a rest application using spring-boot 2.0.3. From an other maven module (in a different multi module pom), I have an integration test that tests that data sent to the running rest application is processed.
Is it possible to run this spring-boot application programatically? I cannot use the simple #SpringBootTest-annotation as the spring-boot application is not in the same maven multi module.
I would recommend using mockito to mock a request to your rest endpoint with some data, and testing that your other application tries to send the correct data to the endpoint.
This way both applications are tested independently and do not have dependencies at each other. This provides the benefit of being able to substitute one of these applications with another if necessary. Also it provides a good separation. This is important because when you (or someone else) wants to use your REST application they do not use your other application so it is very important that the REST application is tested with static data written in your tests and is not dependent on the output of another application. Since REST applications are meant to be independent.
However, when you do want to test it this way you could try to include your other application in the classpath.
The thing is "loose coupling". It is technical possible, but not recommended. The build itself has numerous tests using where mocking with Mockito is essential.
An integration test module, ala cucumber.io, should be created which will cover the functionality of the running module.
This is the main-point of the accepted answer.

How to verify that a spring-boot web server is running

I am writing an integration test for a spring-boot web server
I want to use junit-jupiter (junit5) to check if the server is running using Assumptions.assumeTrue so that the test do not fail if the server is not running...
There seems not to be any API support for such operation, but can it be achieved in some other way? Pinging the server?
You could make use of the actuator module in spring boot. It will provide you with a health check URL and you could make a call to this URL and verify that it returns healthy.
Now that that is out of the way, if you need the server to be running while running your tests, you should probably be using the spring boot test runner, instead of using the JUnit runner. In this case you could still mock some of your spring beans and achieve the same kind of test, but with a spring context running alongside your tests. The downside of this is the overhead of needing to spin up the spring context before running tests, but if you need to use the actual web server, then this is what you should be doing.

Spring boot embedded container or war file in an external container for production

I'm complete able to configure spring boot in both cases, the question here is which of them are more robust and is the more recommended, because I didn't find in the spring boot documentation the recommended way to deploy it in a production environment, my concerns about use the embedded container are:
If I want to set it as a Windows or Linux service, is the jar file the best option?
If I use the jar file I'm not going to have access to restart the server.
Maybe in the future I need more applications in the same container.
If I restart the machine I have to execute again the java -jar.
The question in general is which is better use the jar file and execute it as java -jar jarname.jar in production or change the packaging to war set the tomcat as provided and set the generated war in an empty tomcat.
I hope you can help me.
---EDIT---
Many times the answer is depends, this is for a normal web application or REST web service.
jar packaging is perfectly suitable for production and you should rather fallback to war only if you really have to - which is often the case when you cannot control your deployment environment (which is often the case in large enterprises).
There is a chapter in Spring Boot Reference about setting up Spring Boot based application as a Unix/Linux/Windows service: Installing Spring Boot applications.
Regarding your concern:
Maybe in the future I need more applications in the same container.
With embedded containers if you need more applications running on the same machine, you should start two applications separately, each running on different port and effectively you will end up with two containers running - which is good, applications are better isolated from each other.
About a month ago I had the question like yours.
Let me share my conclusion:
1) JAR:
You can run independently every appliction with different ports (in linux, java -jar ... > app_logs.log &) and you can route it (e.g. nginx). Note that, restarting is not problem. You can write custom bash script (like this: ps aux | grep appname and kill by PID)
But there are some problems with configuring production app. Property files will archived into jar.
2) WAR
You can deploy into container and just run it. Easy managing at the server. If you want to re-configure app, open properties file from unarchived folder inside container, change it as need and restart container. So, managing and configuring will be easy.
But, if you want to run another app in this server with another port, then you must install another copy of container and config it.
So, in my practice, using war app easier than jar to manage and re-configure.
I don't know that much about Windows services but on Linux you can add the execution of a jar to a RC-Scripts (and thus make the application start at a certain run-level). For a spring boot app you just have to symlink to the jar and you can start/stop/etc like any other service, see: Spring Boot application as a Service
restart the machine or the JVM? A shutdown mechanism is built into spring boot, you just have to activate it (and you should enable security machanism so that not anybody can do that), see: How to shutdown a Spring Boot Application in a correct way?
Spring-Boot enables microservices - so the idea is to have one embedded webapp-container for each webapp/microservice. This reduces the risk of losing all services when only one is going down.
Yes. and you have to execute catalina.sh|bat start after every restart. Or you add an appropriate startup script (see 1.)
I sense that you'd rather do it the old-fashioned way. Despite the 'matter of taste' answer, there is one argument pro-jar: the only dependency is the JVM! The rest (the web-app-container, db-drivers, other libraries) is all part of the package you deliver. And if you decide to change the container for the next release, so will it be.
One more reason to use "war" file in production.
Springboot masked an error Jetty threw whereas WAR deployed in Jetty correctly caught it ( though issue below is still under review )
https://github.com/spring-projects/spring-boot/issues/8917#issuecomment-294673487
I don't know much about server kind of things, But my recommendation is
If you are using Monolithic application, better to use war with
external tomcat.
If you are using for Micro Service applications, use embedded
tomcat with different port. And each micro service applications are
independent from each other.

Categories