I am using Apache CXF 3.0.0 and have few services defined with JAX-RS configuration. We have hierarchical configuration with Spring Framework. These input/output of these services are JSON strings.
I am searching for a working example of Junit test cases to validate my services. Also configure the test in Maven Build.
I referred https://cwiki.apache.org/confluence/display/CXF20DOC/JAXRS+Testing
Is it recommended approach?
Nevertheless, I tried to setup but could not succeed, could not understand how to wire it.
I like the approach you mention in your link, but it depends on your set up.
I show how I managed to create junit test for cxf server using spring configuration:
// Normal Spring Junit integration in my case with dbunit
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/root-test-context.xml", "classpath:/rest-test-context.xml" })
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DbUnitTestExecutionListener.class })
#DatabaseSetup("AuthenticationResourceTest-dataset.xml")
#DatabaseTearDown("AuthenticationResourceTest-dataset.xml")
public class AuthenticationResourceTest {
// This variable is populated from surfire and reserve port maven plugin
#Value("#{systemProperties['basePath'] ?: \"http://localhost:9080/api/\"}")
private String basePath;
// I assume that you have in your spring context the rest server
#Autowired
private JAXRSServerFactoryBean serverFactory;
private Server server;
#Before
public void beforeMethod() {
serverFactory.setBindingId(JAXRSBindingFactory.JAXRS_BINDING_ID);
// Specify where your rest service will be deployed
serverFactory.setAddress(basePath);
server = serverFactory.create();
server.start();
}
#Test
public void authenticateTest() throws Exception {
// You can test your rest resources here.
// Using client factory
// AutenticationResourceclient = JAXRSClientFactory.create(basePath, AutenticationResource.class);
// Or URLConnection
String query = String.format("invitation=%s", URLEncoder.encode(invitation, "UTF-8"));
URL url = new URL(endpoint + "/auth?" + query);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try (InputStream is = connection.getInputStream();) {
String line;
// read it with BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
#After
public void afterMethod() {
server.stop();
server.destroy();
}
}
You need to have in your maven pom.xml
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.0.2</version>
</dependency>
Plugins section:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>reserve-network-port</id>
<goals>
<goal>reserve-network-port</goal>
</goals>
<phase>process-test-resources</phase>
<configuration>
<portNames>
<portName>test.server.port</portName>
</portNames>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<systemPropertyVariables>
<basePath>http://localhost:${test.server.port}/api</basePath>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
You can check out my from my personal git repository the complete example:
Related
I'm new to the UnitTesting and Cucumber, and today I tried to implement a simple example from a tutorial in Eclipse and I got error when I try run the RunnerClass.java.
My Pom file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>belajar1</groupId>
<artifactId>belajar1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>9</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.0.0-beta4</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>6.10.2</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>6.10.2</version>
</dependency>
</dependencies>
</project>
My feature file
Feature: Gmail Testing
Scenario: Gmail Login
Given url opened
Then enter user id and click next
Then enter password
And click login
Scenario: Gmail Close
Then Close browser
My Definition file
public class stepDefinition {
public static WebDriver obj=null;
#Given("^url opened$")
public void url_opened() throws Throwable{
System.setProperty("webdriver.gecko.driver","D:\\Installed APP\\Eclipse Workspace\\Webdriver\\geckodriver.exe");
obj=new FirefoxDriver();
obj.manage().window().maximize();
obj.get("https://mail.google.com");
}
#Then("enter user id and click next")
public void enter_user_id_and_click_next() throws InterruptedException{
obj.findElement(By.id("Email")).sendKeys("YOURUSERID");
obj.findElement(By.id("next")).click();
Thread.sleep(2000);
}
#Then("^enter password$")
public void enter_password(){
obj.findElement(By.id("Passwd")).sendKeys("YOURPASSWORD");
}
#Then("^click login$")
public void click_login() throws InterruptedException{
obj.findElement(By.id("signIn")).click();
Thread.sleep(6000);
}
#Then("^close browser$")
public void close_browser(){
obj.quit();
}
}
My Runner file
package tester;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
#RunWith(Cucumber.class)
#CucumberOptions(
features="src/test/resources/demo.feature",
glue="definition.stepDefinition",
plugin = {
"pretty",
"html:target/report", //create a folder called cucumber
"json:target/report.json",
//Notice the corresponding file extension (.json) telling cucumber to create a file
// "com.cucumber.listener.ExtentCucumberFormatter:target/report.html"
//Notice I remove the white space at :target/report.html
}
)
public class RunnerClass {
}
I keep got this error
enter image description here
Also this my Library
enter image description here
My request objects are autogenerated through openapi-generator-maven-plugin based on json interface file.
I want to have this annotation #JsonInclude(value = JsonInclude.Include.NON_NULL) on top of one of the autogenerated class's property (not all the classes or the other properties of a class)
following is being autogenerated:
#ApiModel(description = "blabla")
#JsonPropertyOrder({
Request.JSON_PROPERTY_CONSENT_ID,
})
#JsonTypeName("Request")
#javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", date = "2022-02-17T13:14:32.020579400+01:00")
public class Request{
public static final String JSON_PROPERTY_CONSENT_ID = "consentId";
private Long consentId;
#javax.annotation.Nullable
#ApiModelProperty(value = "blabla")
#JsonProperty(JSON_PROPERTY_CONSENT_ID)
#JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public Long getConsentId() {
return consentId;
}
#JsonProperty(JSON_PROPERTY_CONSENT_ID)
#JsonInclude(value = JsonInclude.Include.USE_DEFAULTS)
public void setConsentId(Long consentId) {
this.consentId = consentId;
}
so currently this code is being autogenerated with JsonInclude.Include.USE_DEFAULTS but instead of that i want JsonInclude.Include.NOT_NULL. Can this be achieved ?
i tried using
spring:
jackson:
default-property-inclusion: NON_NULL
in application.yml file but same result with USE_DEFAULTS. I am using spring boot version 2.1.4
I had similar problem. I wanted to generate model class similar to:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
#JsonInclude(JsonInclude.Include.ALWAYS)
private String firstName;
private String middleName;
}
What I did:
I used openapi-generator-maven-plugin version > 6.0.0 that supports x-field-extra-annotation added to specification:
Person:
type: object
properties:
firstName:
type: string
x-field-extra-annotation: "#JsonInclude(JsonInclude.Include.ALWAYS)"
middleName:
type: string
Then I added additional class annotation by:
<configOptions>
<additionalModelTypeAnnotations>
<![CDATA[#JsonInclude(JsonInclude.Include.NON_NULL)]]>
</additionalModelTypeAnnotations>
</configOptions>
Finally I removed default annotations:
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>${replacer.version}</version>
<executions>
<execution>
<id>removeUnusedAnnotations</id>
<phase>process-resources</phase>
<goals>
<goal>replace</goal>
</goals>
<configuration>
<includes>
<include>${openapi-generator-maven-plugin.outputBaseDir}/src/**/*.java</include>
</includes>
<replacements>
<replacement>
<token>#JsonInclude\(value = JsonInclude.Include.USE_DEFAULTS\)</token>
<value />
</replacement>
</replacements>
</configuration>
</execution>
</executions>
</plugin>
Last step is dirty workaround, but couldn't find anything better.
I'm trying to create a simple Junit5-Cucumber project (in Eclipse) that would be used for UI testing.
I took reference from this repo:https://github.com/cucumber/cucumber-java-skeleton
Issue: No definition found for Open the Chrome and launch the application (error happens to the Given, When and Then statements) in the test_features.feature file.
# test_features.feature
Feature: Reset functionality on login page of Application
Scenario: Verification of Reset button
Given Open the Chrome and launch the application
When Enter the username and password
Then Reset the credentials
# RunCucumberTest.java
package lpms.cucumber;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("lpms/cucumber")
#ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
#ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "lpms.cucumber")
public class RunCucumberTest {
}
# StepDefinitions.java
package lpms.cucumber;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class StepDefinitions {
#Given("^Open the Chrome and launch the application$")
public void open_the_chrome_and_launch_the_application() throws Throwable
{
System.out.println("This step opens the chrome and launches the application");
}
#When("^Enter the username and password$")
public void enter_the_username_and_password() throws Throwable
{
System.out.println("This step enters the username and password on the login page");
}
#Then("^Reset the credentials$")
public void reset_the_credential() throws Throwable
{
System.out.println("This step clicks on the reset button.");
}
}
Project Structure
IMAGE OF MY PROJECT STRUCTURE
Solved!
It's a warning from Eclipse IDE, likely just a bug, because I can still get testing done.
Sidenote: Extremely useful guide for learning the latest cucumber: https://cucumber.io/docs/guides/10-minute-tutorial/
I had the same problem on my project and i'll post my solution here.
I've used Eclipse + Java 11 + SpringBoot 2.6.4
pom.xml dependencies
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<scope>test</scope>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>7.3.0</version>
<scope>test</scope>
</dependency>
pom.xml plugin in build section
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<configurationParameters>
cucumber.junit-platform.naming-strategy=long
</configurationParameters>
</properties>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
After that, i've created a package in src/test/java called
filelife/skynet/cucumber
In this package i've created my steps class and my runner class; Steps class contains only some logging instrauctions, it doesn't verify nothing yet.
Steps class:
#Slf4j
public class SendMessagesOnServiceLimitsSteps {
#Given("A ServiceLimits Module with PosTXRate of {int} seconds")
public void a_service_limits_module_with_pos_tx_rate_of_seconds(Integer posTxRate) {
log.info("ServiceLimits PosTxRate {}", posTxRate);
System.out.println("Given Step");
}
#When("I keyOn the device")
public void i_key_on_the_device() {
System.out.println("Given Step");
}
#When("i wait for {int} seconds")
public void i_wait_for_seconds(Integer int1) {
System.out.println("Given Step");
}
#When("i keyOff the device")
public void i_key_off_the_device() {
System.out.println("Given Step");
}
#Then("PositionData messages should be {int} or {int}")
public void position_data_messages_should_be_or(Integer int1, Integer int2) {
System.out.println("Given Step");
}
#Then("device log print {string}")
public void device_log_print(String string) {
System.out.println("Given Step");
}
}
And my runner tests class:
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("filelife/skynet/cucumber")
#ConfigurationParameter(
key = GLUE_PROPERTY_NAME,
value = "filelife.skynet.cucumber"
)
public class SkynetTest{
}
I've also created the same folder path (filelife/skynet/cucumber) in src/test/resources source folder and i've pasted my .feature file.
In the end, i've created 2 files:
cucumber.properties
junit-platform.properties
in same source folder src/test/resources containg, both of them, string:
cucumber.publish.quiet=true
This configuration works with:
mvn tests
and
right click on SkynetTest -> RunAs -> Junit Test
So I have a TeamCity and JUnit tests, and I want to write a RunListener to notify TeamCity in real-time about running tests - TeamCity only supports batched test reporting for JUnit out of box.
I have several suites, annotated with #RunWith(Suite.class) for logical grouping of tests. TeamCity shows tests grouped by suite correctly. However, my problem is that Surefire will only call RunListener.testRunStarted once, with both suites' names in description (but no way to attribute tests to either one).
So I have implemented
public class JUnitTeamcityReporter extends RunListener {
/** */
private volatile Description suite;
/** */
#Override public void testRunStarted(Description desc) {
this.suite = desc;
}
/** */
#Override public void testStarted(Description desc) {
System.out.println(String.format("##teamcity[testStarted name='%s' captureStandardOutput='true']",
testName(suite, desc)));
}
...
And I have hooked it up in my pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<forkCount>0</forkCount>
<properties>
<property>
<name>listener</name>
<value>com.pany.JUnitTeamcityReporter</value>
</property>
</properties>
</configuration>
</plugin>
I run maven with -Dtest=FirstTestSuite,SecondTestSuite
and the output is the following:
[INFO] Tests run: 11, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 16.803 s - in com.pany.FirstTestSuite
# I expect that my RunListener will be notified HERE, but it does not happen!
[INFO] Running com.pany.SecondTestSuite
Otherwise, my solution works fine if there's just one suite per module.
Is it possible to make Surefire report every Suite properly to testRunStarted?
Unfortunately, there does not seem to be a way to get current running suite from test discription, so I don't understand how to work around this.
This information is not available to JUnit, and Surefire has rather poor extension capabilities, but it can be reached:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version> <!-- upgrade to M4 -->
<configuration>
<workingDirectory>${user.dir}</workingDirectory>
<!-- surefire integration to intercept test suite start: -->
<statelessTestsetInfoReporter
implementation="com.pany.TestSuiteAwareTestsetReporter"/>
<properties>
<property>
<name>listener</name>
<value>com.pany.JUnitTeamcityReporter</value>
</property>
</properties>
</configuration>
<dependencies>
<!-- Add dependency to plugin (for surefire) as well as
compile,test dependency to module (for junit) since they're on different classpaths -->
<dependency>
<groupId>com.pany</groupId>
<artifactId>dev-tools</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
and the code of test suite reporter:
public class TestSuiteAwareTestsetReporter extends SurefireStatelessTestsetInfoReporter {
#Override public StatelessTestsetInfoConsoleReportEventListener<WrappedReportEntry, TestSetStats> createListener(
ConsoleLogger log) {
return new ConsoleReporter(log, false, false) {
public void testSetStarting(TestSetReportEntry report) {
MessageBuilder builder = MessageUtils.buffer();
/** #see TestSetStats#concatenateWithTestGroup(MessageBuilder, ReportEntry, boolean) */
JUnitTeamcityReporter.suite = concatenateWithTestGroup(builder, report);
super.testSetStarting(report);
}
};
}
...
I am working with:
Spring Framework 4.3.2
AspectJ 1.8.9
JUnit
Gradle
The project is based in multi-modules.
In src/main/java (main) I have some #Aspect classes and they work how is expected. I can confirm it through Runtime and Testing
Now I need for JUnit through logging show the #Test method name that is executed
Therefore in src/test/java (test) I have the following:
class TestPointcut {
#Pointcut("execution(#org.junit.Test * *())")
public void testPointcut(){}
}
#Aspect
#Component
public class TestAspect {
private static final Logger logger = LoggerFactory.getLogger(TestAspect.class.getSimpleName());
#Before(value="TestPointcut.testPointcut()")
public void beforeAdviceTest(JoinPoint joinPoint){
logger.info("beforeAdviceTest - Test: {} - #Test: {}", joinPoint.getTarget().getClass().getName(), joinPoint.getSignature().getName() );
}
}
Observe the second class has #Aspect and #Component therefore it is recognized by Spring
Note: I can confirm that If I write wrong the #Pointcut syntax or expression I get errors.
The problem is when I execute my #Test methods, For the TestAspect class the #Before advice never works.
I did a research in Google and I have seen that the #Pointcut("execution(#org.junit.Test * *())") pattern is correct.
Even If I use a more explicit such as: #Pointcut(value="execution(public void com.manuel.jordan.controller.persona.*Test.*Test())"), it does not work.
Consider I have the following for Gradle
project(':web-27-rest') {
description 'Web - Rest'
dependencies {
compile project(':web-27-service-api')
testRuntime project(':web-27-aop')
testRuntime project(':web-27-aop').sourceSets.test.output
What is missing or wrong?
Alpha:
One kind of Test classes are:
Server side working with #Parameters and #ClassRule + #Rule
Therefore:
#RunWith(Parameterized.class)
#ContextConfiguration(classes={RootApplicationContext.class})
#Transactional
public class PersonaServiceImplTest {
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE= new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
private PersonaService personaServiceImpl;
...
#Parameters
public static Collection<Persona[]> data() {
.....
});
}
...
#Test
#Sql(scripts={"classpath:....-script.sql"})
public void saveOneTest(){
....
}
Other are:
Web side working with (#WebAppConfiguration) and either:
with #Parameters and #ClassRule + #Rule
without #Parameters and #ClassRule + #Rule
Therefore (below the second approach):
#Transactional
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={RootApplicationContext.class, ServletApplicationContext.class})
public class PersonaDeleteOneControllerTest {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private ResultActions resultActions;
...
#BeforeClass
public static void setUp_(){
...
}
#Before
public void setUp(){
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void deleteOneHtmlGetTest() throws Exception {
JUnit instantiates your test class. Thus, Spring is not involved and therefore cannot apply AOP advice to the test instance.
As was mentioned by Sergey Bespalov, the only way to have AspectJ advice applied to your test instance is to use compile-time or load-time weaving. Note that this would not be configured within Spring. Spring can be used to configure AOP for Spring-managed beans, but the test instance is managed by the testing framework (i.e., JUnit 4 in your scenario).
For tests using the Spring TestContext Framework, however, I would not recommend using AspectJ. Instead, the best solution is to implement a custom TestExecutionListener that performs the logging. You could then register that TestExecutionListener explicitly via #TestExecutionListeners or have it picked up automatically for your entire suite. For the latter, see the discussion on automatic discovery in the Testing chapter of the Spring reference manual.
Regards,
Sam (author of the Spring TestContext Framework)
You can use AspectJ Compile or Load time weaving as alternative of spring-aop proxying. In such approach you will not depend on spring context complicated logic to apply advices in your code. Aspect code will be just inlined during compilation or class loading phase.
Example below shows how to enable AspectJ Compile Time Weaving:
pom.xml
This Maven configuration enables AspectJ compiler that makes bytecode post processing of your classes.
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
</dependencies>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.6</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>${java.source}</source>
<target>${java.target}</target>
<complianceLevel>${java.target}</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>false</verbose>
<XnoInline>false</XnoInline>
</configuration>
<executions>
<execution>
<id>aspectj-compile</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>aspectj-compile-test</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
applicationContext.xml
Also you may need to add aspect instance to Spring Application Context for dependency injection.
<bean class="TestAspect" factory-method="aspectOf"/>