How to run my Spring tests before every commit/push? - java

Surprisingly, I was not able to find a this question on this website, so here it comes :
How can I run my Spring tests before every git commit/push (CLI, GUI and IDE integration) and have this command fail on test fail ?
I am aware of the existence of git hooks and run my tests using mvnw test. How to combine this to get the described behavior ?

You can use any (bash) script as a git pre-commit or pre-push hook. Git should abort if the script returns a non-zero return code.
So create a script named pre-commit.tests or pre-push.tests that looks roughly like this
#!/bin/bash
mvnw test
and register the hook, e.g. by placing the script in .git/hooks.
mvn test should already return a non-zero return code if tests fail.
If not you would need to determine whether the tests succeeded in your script. For instance by piping the result to grep and looking for an ERROR entry or a more indicative line that either indicates success or failure.
Note: If you happen to be working in a Windows/Mac environment you'd likely need to adapt this based on how you integrated git, i.e. whether you run in a bash-compatible console or not.

Related

Does equivalent practice of package.json scripts from NPM exists in Java(maven)?

I've been trying to find the equivalent of sctipts in NPM for Java and had no luck.
Makes me wonder if it's even possible, but I assume it is, it's just probably very hard to find.
My main goal is to avoid my Readme.md file containing long commands, and would like very much to have something similar with npm scripts, which would trigger a certain line based on a certain keyword.
For example, I would like to create something like this:
"smoke" : "mvn clean test -Dsmoke="src/test/smokeSuite.xml""
or
"smoke" : "clean test -Dsmoke="src/test/smokeSuite.xml""
Which would then be run by a simple mvn smoke command.
Is it possible?

How to pass environment variables to the gradle wrapper build using only command line?

I am trying to pass env variables locally with strictly a command line command. At deploy, these variables get passed into the docker container, but when running locally, they are not present and need to be set locally.
They need to be removed before committing though because they are access keys so i dont want them exposed in the repo. That is why running tests locally (without an IDE) would require a command that passes these variables.
I have already tried this:
./gradlew clean build -Dspring.profiles.active=local -DMY_ENV_VAR1=xxxxxx -DMY_ENV_VAR2=xxxxxx
and it doesnt seem to be working. i cant find the docs for the build command's options, but i thought this was how you pass them. what am i doing wrong here? or is it not possible?
Another reason for environment variables not working is the gradle daemon.
Run this to kill any old daemons:
./gradlew --stop
Then try again. Lost far too much time on that.
For passing env variables
MY_ENV_VAR1=xxxxxx MY_ENV_VAR2=xxxxxx ./gradlew bootRun
For arguments/overriding properties values
./gradlew bootRun --args='--spring.profiles.active=local --db.url=something --anotherprop=fafdf'
For both passing env variable and overriding properties values.
MY_ENV_VAR1=xxxxxx MY_ENV_VAR2=xxxxxx ./gradlew bootRun --args='--spring.profiles.active=local --db.url=something --anotherprop=fafdf'
This related post worked for me: https://stackoverflow.com/a/57890208/1441210
The solution was to use the --args option of gradlew to get the environment variable to be passed to the spring boot app:
./gradlew bootRun --args='--spring.profiles.active=local'
I just put the env variable setting before calling command as the way a regular Unix shell does. Work with my Zsh.
MY_ENV_VAR1=xxxxxx MY_ENV_VAR2=xxxxxx gradlew clean test
If you want to pass values to the JVM that runs the gradle you can use the '-D' switch. I suppose you have to pass values to the gradle build file from the command line. If that's the case there are two options for that:
You can use the -P switch and specify the value there. For example:
gradle -PmySecretKey="This key is so secret" yourTask
If you are using linux or variants you can set environment variable as follows:
export ORG_GRADLE_PROJECT_mySecretKey="This key is so secret"
After this you can access the value in the gradle build file as follows (I am using kotlin dsl)
val mySecretKey: String by project
println(mySecretKey)
To answer your question, as far as I know, there's no way to set environment variables manually through Gradle. What your doing right now is just passing in regular CLI arguments/parameters to your tests.
when running locally, they are not present and need to be set locally.
running tests locally (without an IDE) would require a command that passes these variables.
I see from your snippet, you are using Spring, likely Spring Boot. And since you're already specifying the profile as local, why not define these variables in a profile specific configuration? Example:
application.yml -- base configuration
my-config-value: ${MY_ENV_VAR}
application-local.yml -- local profile configuration that overrides the base
my-config-value: some-dummy-value-for-local-development

One selenium test automation project run on few environments

I have a single test automation project with test scripts which is integrated with VSTS and jenkins. It means VSTS build step run Jenkins job and after this test scripts are running on remote machine, but I have hardcoded URL in my driver.get(url just for test env, but I need run on dev or prod env) method.
So my question is how to parameterize driver.get(parameter) method to still use this one project and run test scripts on many env not just on test env?
For example: If new build queued is on QA branch then run scripts on http://QAenv.app.com else if queued on PROD branch then run scripts on http://PRODenv.app.com.
What about storing it in properties and reading it?
Example:
driver.get(System.getProperty("myPropertyKey", "http://myDefaultTestUrl"));
Regarding Jenkins Queue Job step/task, you can specify Job parameters.
For the example you provided, you can add a variable to the build definition and change the value per to predefined variables (e.g. Build.SourceBranch ), then specify the variable in Jenkins Queue Job step/task.
Regarding set variable value, you can use Write-Host "##vso[task.setvariable variable=testvar;]testvalue", more information, you can refer to: Logging Commands

java continuous testing outside of IDE

I have a bunch of Java unit tests, and I'd like to integrate a continuous testing framework into my codebase. Ideally, I would like to write a Maven / Ant target or bash script which would start running tests whenever the files it's watching change. I've looked at a couple of options so far (Infinitest, JUnit Max) but both of them appear to want to run as IDE plugins.
My motivation for using a CLI-only tool is that my coworkers use a broad set of text editors and IDEs, but I want to ensure that anyone can run the tests constantly.
EDIT: I did not consider Jenkins or other more typical CI solutions for several reasons:
We already have a CI build tool for running unit and integration tests after every push.
They hide the runtime of the tests (because they run asynchronously), allowing tests to become slower and slower without people really noticing.
They usually only run tests if your repository is in some central location. I want unit tests to be running while I'm editing, not after I've already pushed the code somewhere. The sooner I run the tests, the sooner I can fix whatever mistake I made while editing. Our JavaScript team has loved a similar tool, quoting speedup of 3x for iterating on unit test development.
I am using a continuous polling for directory change solution for that. ( general code: http://www.qualityontime.eu/articles/directory-watcher/groovy-poll-watcher/ (in Hungarian, but source code is English) )
A customized solution for compiling nanoc based site. Review and customize to your need. (Groovy)
def job = {
String command = /java -jar jruby-nanoc2.jar -S nanoc compile/
println "Executing "+command
def proc = command.execute()
proc.waitForProcessOutput(System.out, System.err)
}
params = [
closure: job,
sleepInterval: 1000,
dirPath: /R:\java\dev\eclipse_workspaces\project\help\content/
]
import groovy.transform.Canonical;
#Canonical
class AutoRunner{
def closure
def sleepInterval = 3000
// running for 8 hours then stop automatically if checking every 3 seconds
def nrOfRepeat = 9600
def dirPath = "."
long lastModified = 0
def autorun(){
println "Press CTRL+C to stop..."
println this
def to_run = {
while(nrOfRepeat--){
sleep(sleepInterval)
if(anyChange()){
closure()
}
}
} as Runnable
Thread runner = new Thread(to_run)
runner.start()
}
def boolean anyChange(){
def max = lastModified
new File(dirPath).eachFileRecurse {
if(it.name.endsWith('txt') && it.lastModified() > max){
max = it.lastModified()
}
}
if(max > lastModified){
lastModified = max
return true
}
return false;
}
}
new AutoRunner(params).autorun()
Why not use a CI tool like Jenkins to run your tests on every code change, as part of your overall CI build? It's easy to get Jenkins to poll your source control system and run a build or separate test job when a file changes.
Usual way is to use a Continuous Integration server such as Jenkins.
Have Jenkins poll your version control system every 15 minutes and it will build your project as it notices commits. You will never be far away from knowing that your source code works.
I would recommend to use a CI tool such as Jenkins, where you have the possibility not only to install on premise, but also to get a Jenkins cloud instance through a PaaS where you can easily test if this solution could meet or not your goal without spending too much time in the set-up process.
This PaaS provides some ClickStarts that you can use as a template for your own projects, on premise or on the cloud. It will generates you a Jenkins job fully set-up and working.
Some articles that you can take a look at are:
Painless Maven Builds with Jenkins where you can see the dashboard you can get. You will see the maven tests which are passed per build and you can also get a graph showing the maven tests passed, skipped and failed.
iOS dev: How to setup quality metrics on your Jenkins job? Although this article talks specifically about iOS, you can also get the same goal for a standard java maven project: Test coverage, Test results, Code duplication, Code metrics (LOC), ...
Yeah having a build server (like Bamboo, Cruise Control er TeamCity) and a build tool like Maven (along with surefire-plugin for TestNg/Junit and Failsafe-plugin for integration testing maybe using something like Selenium 2) is quite popular, because it's relatively trivial to setup (works almost out-of-the-box). :)

How to run Tests when developing javaagents?

I'm trying to fiddle with Foursquare's HeapAudit, and am attempting to set it up using IntelliJ IDEA. I have managed to get it to build just fine, using the dependencies from the pom.xml.
However, when I actually try to run the JUnit tests, basically all of them fail. I'm guessing this is because using HeapAudit requires the JVM to be started with it as a -javaagent, according to the github:
$ java -javaagent:heapaudit.jar MyTest
Presumably the tests would pass if I put this line in, and referenced the heapaudit.jar i downloaded/built earlier. However, it seems to me that if I make changes the the source, I'm gonna need to re-package this silly .jar file in order to see if it works.
Is there any way of running the tests with a -javaagent without going through the whole rigmarole of compile -> package-into-jar every testing cycle? Perhaps getting IntelliJ to attached the newly-compiled .class files as a -javaagent before running the tests?
1) Have a jar just with a META-INF/MANIFEST.MF
The manifest must be properly configured with Premain-Class and other attributes. The jar doesn't need any other files. Use this jar with the -javaagent. Provided that the agent classes are in the classpath, the agent will start normally.
This might fail when using maven-surefire-plugin with forkMode=never because by default the application classes are loaded in a child ClassLoader.
Works fine with Eclipse and Intellij.
If doing this, double check the manifest syntax (once I spent a long time to figure out that a package name was wrong).
2) Use ea-agent-loader
It will allow you to load the agent (any agent) in runtime (it uses VM.attach()). However the VM.attach() sometimes disrupts debugging and breakpoints might fail to trigger.
It will have the same issues with the surefire in forkMode=never
3) Load the agent in runtime.
Write your on code to load the agent in runtime. And call it from your #BeforeClass You will still need a jar (which you can generate in runtime if you want).
Just you need to call this (only once):
AgentLoader.loadAgentClass(YourAgentClass.class.getName());

Categories