Auto-Restart for Spring Boot Tests - spring-boot

I am currently writing unit and integration tests for a Spring Boot application. I'm using Spring Tool Suites 4 for development.
When I run the application using Spring Tool Suites, the auto-restart works fine when I modify and save a file. I'm trying to find a similar way to run my tests.
I currently run the tests using a separate Windows CMD terminal using Maven:
mvn test
This runs one time and terminates. Is there anyway to have the tests run every time a test file is saved?
Edit: Here's an example of a test I am running that uses JUnit and Spring to run the tests. This is taken straight from the Spring.io website https://spring.io/guides/gs/testing-web/
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
#SpringBootTest
public class ControllerTest {
#Autowired
private Controller controller;
#Test
public void contexLoads() throws Exception {
assertThat(controller).isNotNull();
}
}

I found this Maven plugin https://github.com/fizzed/maven-plugins#watcher-fizzed-watcher-maven-plugin that will watch files and let you run specific Maven goals on file changes.
I added the plugin to my POM and changed the goal to "test".
<build>
<plugins>
<plugin>
<groupId>com.fizzed</groupId>
<artifactId>fizzed-watcher-maven-plugin</artifactId>
<version>1.0.6</version>
<configuration>
<touchFile>target/classes/watcher.txt</touchFile>
<watches>
<watch>
<directory>src/main/java</directory>
</watch>
<watch>
<directory>src/test/java</directory>
</watch>
</watches>
<goals>
<goal>test</goal>
</goals>
</configuration>
</plugin>
<plugins>
<build>
I opened a terminal within Spring Tool Suites (ctrl + alt + t) and docked it next to my console and ran the following:
mvn fizzed-watcher:run
So far this seems to be working exactly like I want.

Related

How to pass profile while running mvn test for a springboot application

I am trying to run test cases of spring boot application.
For that I tried using mvn test -Dspring.profiles.active=test.
But it did not work.
Do I need to add profile in pom.xml
Could you please help.
The java arguments come before the maven lifecycle parameter:
mvn -Dspring.profiles.active=test test
You can also add <argLine> property to maven surefire plugin to apply to all tests.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<testEnvironment>true</testEnvironment>
</systemPropertyVariables>
<argLine>-Dspring.profiles.active=test</argLine>
</configuration>
</plugin>
The best way to run a test with a profile is using the ActiveProfiles annotation (assuming JUnit 5):
#SpringBootTest
#ActiveProfiles("test")
class MyApplicationTest {
#Test
void test() {
// implement actual test here
}
}
This will start your Spring Application with the test profile active.

Glue code is not loaded when running with cucumber-spring back-end from jar file

I have been trying to get spring-based cucumber tests to run using a combination of Junit(4.12), Cucumber-Java(4.1.1), Cucumber-Spring(4.1.1) and Cucumber-Junit(4.1.1).
I have no issues loading glue code when running the tests from inside the IDE (IntelliJ 2018.3.4) but it seems that for some reason when I try running from the a compiled jar file (which is a requirement in this case) cucumber doesn't find the step definitions.
I've already tried multiple glue code formats such as:
"classpath:com.a.b.c.stepdefs"
"com.a.b.c.stepdefs"
"classpath:com/a/b/c/stepdefs"
I've also tried providing relative paths from the runner class up to the step definitions class (nested just one level below)
"stepdefs"
Also gave a try running using both JUnit and the cucumber.cli.Main and attempted to use different style of step definitions (both cucumber expression - which the missing step snippets are pointing me to - and regex)
I am using the spring-boot-maven-plugin so I am aware that that generally changes the jar structure
All of the above variations fully work when running from the IDE, but not from the jar file
Main Class:
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
#ComponentScan(basePackages = {"com.a.b.test.core.data",
"com.a.b.c",
"com.a.b.c.stepdefs"}
)
public class CucumberApplication {
public static void main(String[] args) throws IOException, InterruptedException {
SpringApplication.run(CucumberApplication.class, args);
Result result = JUnitCore.runClasses(RunnerCentral.class);
System.exit(result.wasSuccessful() ? 0 : 1);
}
}
Runner Class:
package com.a.b.c;
#RunWith(Cucumber.class)
#CucumberOptions(features = "classpath:BOOT-INF/classes/features",
glue = "classpath:com/a/b/c/stepdefs",
plugin = "json:target/cucumber-html-reports/cucumber.json")
public class RunnerCentral {
}
POM config of spring-boot-maven-plugin:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.0.RELEASE</version>
<configuration>
<fork>true</fork>
<mainClass>${start-class}</mainClass>
<requiresUnpack>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-spring</artifactId>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
</dependency>
</requiresUnpack>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
I am expecting the behavior to be consistent between running from IDE and running from a packaged source although I may be missing something
Another thing I want to mention is that when swapping the backend with cucumber-picocontainer everything seems to work (spring is a requirement so a swap isn't possible)
This is the kind of issue that can have you launching your hot coffee at the nearest colleague.
Have you seen this post about using a custom ResourceLoader https://github.com/cucumber/cucumber-jvm/issues/1320
I think you'd have to copy and paste the Cucumber.java class, providing the resource loader to the runtime from the Application Context, and change your RunnerCentral class to RunWith the new class.
FWIW in my case, I placed the raw project in a docker container, that on startup ran ./mvnw test which is the Maven Wrapper supplied in Spring Boot projects. You can do ./mvnw test -s /path/to/maven/settings.xml if using a corporate repository, and if your container host can't access the corporate repository, run the image first on the Jenkins box (or wherever the image is being built) which will cause the dependency jars to be downloaded inside, then commit the docker image, and push that image out.
That way, the container can run the cucumber test phase using the local .m2 directory inside it, with the dependencies it needs already there.

Kick off Spring Boot & make a call using a maven profile

I have an existing application which is a jetty app written in Java and managed with maven. There are a few basic tasks that can be run from the browser but mainly it runs all the tasks in one go when run from the command line (or Jenkins).
It does this by calling a specific Maven profile
so the maven command line call is
mvn clean install -P autorun
The autorun profile is
<profile>
<id>autorun</id>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>install</phase>
<configuration>
<target>
<property name="runtime_classpath" refid="maven.runtime.classpath"/>
<java classname="com.app.tool.Client" >
<arg value="-h" />
<classpath>
<pathelement path="${runtime_classpath}"/>
</classpath>
</java>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
there is a main procedure in the Client class
public static void main(String... args) throws Exception { ...
which essentially
creates an org.eclipse.jetty.server.Server object
uses the war file to kick off the http server app
Uses a number of org.springframework.http.client.ClientHttpRequest objects to fire off a number of tasks using code along the lines of
ClientHttpRequest request = restTemplate
.getRequestFactory()
.createRequest(
new URI("http://localhost:8080/tool/spring/" + jobName),
HttpMethod.GET);
ClientHttpResponse clientHttpResponse = request.execute();
if (clientHttpResponse.getStatusCode().value() != HttpStatus.OK_200) {
throw new RuntimeException(...);
}
I am going to refactor the app now for various reasons. My aim is to keep the current design as, although it's main current use points more to a console app, I would like to make add some more useful interactive functionality.
So to finally get to the point, I have started re-writing the app as a Spring Boot application. I would like to still be able to fire off the jobs I want from the command line (and Jenkins). Is there a simple (& equivalent) way to do this with Spring Boot & Maven ? I am using Main to fire off the app so possibly I need to pass a switch into here
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootStartUpConfig.class, args);
}
I'm guessing that a lot of the code currently used to start the server can be dumped but I'm struggling to find the best way to achieve this ? (I'd prefer to use Maven as this is the core tool we are using but I can use Gradle if this is something that it is better at).
To run a spring boot application from command line you could include the spring boot maven plugin see reference here
Spring boot maven plugin
and then launch it from command line using
mvn spring-boot:run

JAR file not visible in Java Request sampler of Jmeter

I am using JAVA Request sample in Jmeter to do performance testing of my Selenium TestNG script.
I have created JAR file of my selenium project using maven plugin :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
Kept JAR file under Jmeter/lib/ext folder.
Create Java request sample in Jmeter and check JAR files in Java request Class name but JAR file not reflected.
Also added Selenium Java JAR & Selenium standalone JAR files in Jmeter/lib folder.
Please guide me to resolve this issue.
Thanks..
I run into the same problem when i compiled the jar with a newer version of java. JVM is 1.7 (jmeter.JMeter: java.version=1.7.0_75) and jar made with 1.8 for example. Try using your java -version level for compileing the jar.
If you intent to use Java Request Sampler your class should inherit from AbstractJavaSamplerClient class and override runTest method. Something like:
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
public class Mytest extends AbstractJavaSamplerClient {
#Override
public SampleResult runTest(JavaSamplerContext context) {
//your Selenium code here
return null;
}
If your tests are in JUnit format you can use JUnit Request Sampler instead. Just put your jars under /lib/junit folder of your JMeter installation and JMeter should pick them up. See How to Use JUnit With JMeter guide for comprehensive information on the integration
Are you aware of the WebDriver Sampler which provides Selenium integration almost out of the box?
Remember that you need to restart JMeter after adding or updating any .jar in its classpath or installing a plugin.

Configure Maven to use CXF wsdl2java with Basic Authentication

I have an application that needs to integrate with one of SharePoint's web services. This web service cannot be accessed freely and needs authentication.
As such, the standard wsdl2java Maven plugin in my application gives an HTTP 401 error when the generate-sources phase is executed.
Is there a way to setup Maven/POM so that I can provide a user/password that will generate the stubs?
I have come across some answers saying this is not possible but all answers are older than 1 year. I haven't found if Maven have issued an update on this. One option is to save a local copy of the WSDL (as suggested here) but I would like to avoid having local copies.
Because you mentioned CXF then I suppose you meant cxf-codegen-plugin. It's a bit of a hack but it works.
HTTP authentication credentials can be provided using java.net.Authenticator. One need to just define his own Authenticator class which overrides getPasswordAuthentication(..) method. Then it has to be set as default Authenticator. As far as I know it can't be done declaratively (for instance using environment properties) only programatically using Authenticator.setDefault(..).
In order to call Authenticator.setDefault(..) I would use CXF extension mechanism. Create separate maven project with similar class:
public class AuthenticatorReplacer {
public AuthenticatorReplacer(Bus bus) {
java.net.Authenticator.setDefault(new java.net.Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("test", "test123"
.toCharArray());
}
});
}
}
and file src\main\resources\META-INF\cxf\bus-extensions.txt with contents:
org.example.AuthenticatorReplacer::false
Then add newly created project as a dependency to cxf-codegen-plugin:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${project.version}</version>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>cxf-authenticator-replacer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
...
</plugin>
This way AuthenticatorReplacer is initialized by CXF extension mechanism and replaces default Authenticator with ours.
An clean alternative to #Dawid Pytel's solution would be to run this class during lifecycle of wsdl class auto generation:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>path.to.AuthenticatorReplacer</mainClass>
</configuration>
</plugin>
Important: your AuthenticatorReplacer has to be a main(String[] args) class and running the code inside.
I verified that Dawid's solution works. Alternatively, you can use SoapUI to pull down and cache the wsdl and then use SoapUi code generation support to use cxf to generate the code.
http://java.dzone.com/tips/generating-client-java-code
Dawid's solution works for me too. It is a little tricky though. In Eclipse, the pom.xml keeps complaining that "wsdl2java failed: Could not load extension class AuthenticatorReplacer". You have to ignore this error message and use the command line:
mvn generate-sources
The Java classes will then be generated successfully.

Resources