In my Java and maven project I have used cucumber for BDD test.
Here is the dependency I use:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.2.0</version>
</dependency>
my Hooks class:
import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.AfterStep;
import cucumber.api.java.BeforeStep;
public class Hooks {
#Before
public void init() {
System.out.println( " Before Scenario " );
}
#After
public void cleanUp() {
System.out.println( " After Scenario " );
}
#BeforeStep
public void beforeStep() {
System.out.println("======> This is before step <======");
//Do something before executing the step
}
#AfterStep
public void afterStep() {
System.out.println("======> This is after step <======");
}
}
But when I run my cucumber test it just prints Before Scenario, and After Scenario. Meanwhile, I expect to see, This is before step, and This is after step
before, and after each step.
So, why #AfterStep, and #BeforeStep do not work?
you should provide a small example which others can use to reproduce your problem
Have a look at this small snippet which is working
Assume the following structure
pom.xml
src/test/java/TestRunner.java
src/test/java/stepdefs/StepDefinitions.java
src/test/java/stepdefs/Hooks.java
src/test/resource/features/demo.feature
pom.xml
...
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<version.cucumber>4.2.0</version.cucumber>
</properties>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
</dependencies>
...
TestRunner.java
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/resource/features"},
glue = {"stepdefs"}
)
public class TestRunner {
}
StepDefinitions.java
package stepdefs;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
public class StepDefinitions {
#Given("^a successful step$")
public void aSuccessfulStep() {
System.out.println(" aSuccessfulStep()");
}
#When("doing something")
public void doingSomething() {
System.out.println(" doingSomething()");
}
#Then("something happen")
public void somethingHappen() {
System.out.println(" somethingHappen()");
}
}
Hooks.java
package stepdefs;
import cucumber.api.java.After;
import cucumber.api.java.AfterStep;
import cucumber.api.java.Before;
import cucumber.api.java.BeforeStep;
public class Hooks {
#Before
public void init() {
System.out.println("#Before scenario");
}
#After
public void cleanUp() {
System.out.println("#After scenario");
}
#BeforeStep
public void beforeStep() {
System.out.println(" #BeforeStep");
}
#AfterStep
public void afterStep() {
System.out.println(" #AfterStep");
}
}
demo.feature
Feature: Test cucumber reporting plugin
Scenario: Run a non failing scenario
Given a successful step
When doing something
Then something happen
running the tests
$ mvn clean test
produces following output
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestRunner
#Before scenario
#BeforeStep
aSuccessfulStep()
#AfterStep
#BeforeStep
doingSomething()
#AfterStep
#BeforeStep
somethingHappen()
#AfterStep
#After scenario
1 Scenarios (1 passed)
3 Steps (3 passed)
Related
I'm trying to add some unit tests (using JUnit5) to my application. But trying to autowire a controller raises an assertion error because the controller is null.
Test class:
package com.mydomain.preview.web;
import static org.assertj.core.api.Assertions.assertThat;
import com.mydomain.preview.web.rest.TestController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
#SpringBootTest
public class Test1 {
#Autowired
private TestController controller;
#Test
public void testContext() throws Exception {
assertThat(controller).isNotNull();
}
}
Controller class:
package com.mydomain.preview.web.rest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class TestController {
#RequestMapping
public #ResponseBody String greeting() {
return "Hello World";
}
}
pom.xml (irrelevant sections omitted for brevity):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- junit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
I followed this guide: https://spring.io/guides/gs/testing-web/
The error I'm getting is: java.lang.AssertionError: Expecting actual not to be null. Same error is raised for mvn test, ./mvnw test and running the test from IntelliJ IDEA IDE.
SpringBootApplication Class:
#SpringBootApplication
#EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class})
public class MyApp {
private static final Logger log = LoggerFactory.getLogger(MyApp.class);
private final Environment env;
public MyApp(Environment env) {
this.env = env;
}
#PostConstruct
public void initApplication() {
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
log.error("You have misconfigured your application! It should not run " +
"with both the 'dev' and 'prod' profiles at the same time.");
}
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) {
log.error("You have misconfigured your application! It should not " +
"run with both the 'dev' and 'cloud' profiles at the same time.");
}
}
/**
* Main method, used to run the application.
*
* #param args the command line arguments
*/
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApp.class);
DefaultProfileUtil.addDefaultProfile(app);
Environment env = app.run(args).getEnvironment();
logApplicationStartup(env);
}
private static void logApplicationStartup(Environment env) {
String protocol = "http";
if (env.getProperty("server.ssl.key-store") != null) {
protocol = "https";
}
String serverPort = env.getProperty("server.port");
String contextPath = env.getProperty("server.servlet.context-path");
if (StringUtils.isBlank(contextPath)) {
contextPath = "/";
}
String hostAddress = "localhost";
try {
hostAddress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.warn("The host name could not be determined, using `localhost` as fallback");
}
log.info("\n----------------------------------------------------------\n\t" +
"Application '{}' is running! Access URLs:\n\t" +
"Local: \t\t{}://localhost:{}{}\n\t" +
"External: \t{}://{}:{}{}\n\t" +
"Profile(s): \t{}\n----------------------------------------------------------",
env.getProperty("spring.application.name"),
protocol,
serverPort,
contextPath,
protocol,
hostAddress,
serverPort,
contextPath,
env.getActiveProfiles());
}
}
I assume that #SpringBootTest doesn't find the classes that need to be tested. Try adding #SpringBootTest(classes = {TestController.class})
I tried this locally and it works...
Only thing I found that didn't make sense was that assertThat(controller).isNotNull(); takes two arguments. Try instead assertNotNull(controller)
I am pretty new to Spring Boot, Apache Camel and the ActiveMQ broker. I am trying to create an application which will send a message to a queue which I am hosting locally using Camel for routing.
POM:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.22.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-activemq</artifactId>
<version>3.2.0</version>
</dependency>
MsgRouteBuilder:
public void configure() throws Exception {
from("direct:firstRoute")
.setBody(constant("Hello"))
.to("activemq:queue:myQueue");
}
application.yaml:
activemq:
broker-url: tcp://localhost:61616
user: meAd
password: meAd
MainApp.java:
package me.ad.myCamel;
import org.apache.camel.CamelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import me.ad.myCamel.router.MessageRouteBuilder;
#SpringBootApplication
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableCaching
public class MeAdApp implements CommandLineRunner {
private static final Logger LOG = LoggerFactory.getLogger(MeAdApp.class);
public static void main(String[] args) {
try {
SpringApplication.run(MeAdApp.class, args);
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
}
}
#Override
public void run(String... args) throws Exception {
LOG.info("Starting MeAdApp...");
}
}
MyController.java :
#GetMapping(value = "/routing")
public boolean sendToMyQueue() {
sendMyInfo.startRouting();
return true;
}
SendMyInfo.java :
MsgRouteBuilder routeBuilder = new MsgRouteBuilder();
CamelContext ctx = new DefaultCamelContext();
public void startRouting(){
try {
ctx.addRoutes(routeBuilder);
ctx.start();
Thread.sleep(5 * 60 * 1000);
ctx.stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
So, whenever I call my rest end point: /routing, I get the error:
java.lang.NoSuchMethodError: org.apache.camel.RuntimeCamelException.wrapRuntimeException(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;`
Can anybody please point me to the right direction as to why I am getting this error? Any help is greatly appreciated .
You need to have the components of the same version. If you are using camel-core with 3.2.0, use camel-activemq 3.2.0. And, since you are using spring-boot, you can make use of the starter dependencies. Just add these and you are good to go.
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-activemq-starter</artifactId>
<version>3.2.0</version>
</dependency>
I am a beginner in Cucumber and i have written a basic tests for login and going to the homepage using in a maven project. I suspect there is some consistency issue with POM.xml.
Please find below the files
I have tried with multiple combinations for the dependencies in pom file but seems the issue persists.
1) stepdefination file
package StepDefinition;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class loginStepDefinition {
WebDriver driver;
#Given("^User is already on login page$")
public void user_already_on_login_page(){
System.setProperty("webdriver.chrome.driver","/Users/nilesh.gupta/Desktop/chromedriver" );
driver = new ChromeDriver();
driver.get("https://classic.crmpro.com");
}
#When("^Tittle of login page is Free CRM$")
public void tittle_login_page_is_Free_CRM() {
String tittle = driver.getTitle();
System.out.println("tittle is : " + tittle);
Assert.assertEquals("#1 Free CRM for Any Business: Online Customer Relationship Software", tittle);
}
#Then("^User enters username and password$")
public void user_enters_username_and_password() {
driver.findElement(By.xpath("/html/body/div[2]/div/div[3]/form/div/input[1]\n" )).sendKeys("naveenk");
driver.findElement(By.xpath("/html/body/div[2]/div/div[3]/form/div/input[2]\n" )).sendKeys("test#123");
}
#Then("^User clicks on login button$")
public void user_clicks_on_login_button() {
driver.findElement(By.className("btn btn-small")).click();
}
#Then("^User is on Home Page$")
public void user_is_on_Home_Page() {
String tittle= driver.getTitle();
System.out.println("tittle is : " + tittle );
Assert.assertEquals("CRMPRO", tittle);
}
}
login.feature
Feature: Free CRM Login Feature
Scenario: Free CRM Login Test Scenario
Given User is already on login page
When Tittle of login page is Free CRM
Then User enters username and password
Then User clicks on login button
Then User is on Home Page
testrunner.java
package MyRunner;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
#RunWith(Cucumber.class)
#CucumberOptions(
features = "/Users/nilesh.gupta/eclipse-workspace/CucumberBDD/src/main/java/Features/login.feature",
glue={"stepDefinition"}
/*format={"pretty","html:test-output"}*/
)
public class testRunner {
}
pom.xml
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>CucumberBDD</groupId>
<artifactId>CucumberBDD</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>CucumberBDD</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<cucumber.version>4.8.0</cucumber.version>
<selenium.version>3.5.3</selenium.version>
</properties>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>${selenium.version}</version>
</dependency>
</dependencies>
</project>
Output
There were undefined steps. You can implement missing steps with the snippets below:
#Given("User is already on login page")
public void user_is_already_on_login_page() {
// Write code here that turns the phrase above into concrete actions
throw new cucumber.api.PendingException();
}
#When("Tittle of login page is Free CRM")
public void tittle_of_login_page_is_Free_CRM() {
// Write code here that turns the phrase above into concrete actions
throw new cucumber.api.PendingException();
}
#Then("User enters username and password")
public void user_enters_username_and_password() {
// Write code here that turns the phrase above into concrete actions
throw new cucumber.api.PendingException();
}
#Then("User clicks on login button")
public void user_clicks_on_login_button() {
// Write code here that turns the phrase above into concrete actions
throw new cucumber.api.PendingException();
}
#Then("User is on Home Page")
public void user_is_on_Home_Page() {
// Write code here that turns the phrase above into concrete actions
throw new cucumber.api.PendingException();
}
Please try to make habit to write testing code in the test folder src/test/java instead of main . Everything that write into src/main/java is per default packaged and deliver to your customer whereas everything that you put into src/test/java is no.
Features Options helps Cucumber to locate the Feature file in the project folder structure.
if the Feature file is in the deep folder structure then please use features = “src/test/features“.
Glue
use to locate the Step Definition file.
Once you make changes then please refer below code for your runner file.
package MyRunner;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions(
features = "src/test/features"
,glue={"src/test/stepDefinition"}
,monochrome = false
)
public class testRunner {
}
Try, replace your code in Runner with this. Rebuild project and close and reopen it.
package MyRunner;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
#RunWith(Cucumber.class)
#CucumberOptions(
features = "src/main/java/Features/login.feature",
glue={"StepDefinition"}
/*format={"pretty","html:test-output"}*/
)
public class testRunner {
}
In your example, I think the actual problem is that you cannot use anchors ^ or $ in your stepdefinitions' (Cucumber Expressions) and it shouldn't be there for newer version of io.cucumber. That style is used for info.cukes version.
It should be
#Given("User is already on login page")
public void user_already_on_login_page(){
System.setProperty("webdriver.chrome.driver","/Users/nilesh.gupta/Desktop/chromedriver" );
driver = new ChromeDriver();
driver.get("https://classic.crmpro.com");
}
Instead of
#Given("^User is already on login page$")
public void user_already_on_login_page(){
System.setProperty("webdriver.chrome.driver","/Users/nilesh.gupta/Desktop/chromedriver" );
driver = new ChromeDriver();
driver.get("https://classic.crmpro.com");
}
I see this is a tough question for Play. A lot of people asked that question, but still it is not clear how to get bytes from request body if content type is not set in Java.
There is a solution in Scala, but it is not working for my case.
I want to use Play to built a http mock server in a test in Java.
#BodyParser.Of(BodyParser.Raw.class) has no sense
package org.dan;
import org.junit.Test;
import play.mvc.BodyParser;
import play.mvc.Result;
import play.server.Server;
//import static play.mvc.Controller.request;
import static play.mvc.Results.ok;
import static play.routing.RoutingDsl.fromComponents;
import static play.server.Server.forRouter;
import static play.mvc.Http.Context.Implicit.request;
public class DemoPlayTest {
#Test
public void run() throws InterruptedException {
Server server = forRouter(
9001,
(components) ->
fromComponents(components)
.POST("/echo")
.routeTo(DemoPlayTest::action)
.build());
Thread.sleep(1111111);
}
#BodyParser.Of(BodyParser.Raw.class)
public static Result action() {
return ok("Gut: " + request().body().asRaw() + "\n");
}
}
Testing:
$ curl -v -X POST -d hello http://localhost:9001/echo
Gut: null
Dependencies:
<play.version>2.6.17</play.version>
<dependency>
<groupId>com.typesafe.play</groupId>
<artifactId>play-server_2.11</artifactId>
<version>${play.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.typesafe.play</groupId>
<artifactId>play-akka-http-server_2.11</artifactId>
<version>${play.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.typesafe.play</groupId>
<artifactId>play-java_2.11</artifactId>
<version>${play.version}</version>
<scope>test</scope>
</dependency>
package org.dan;
import org.junit.Test;
import play.mvc.Result;
import play.server.Server;
import static play.mvc.Controller.request;
import static play.mvc.Results.ok;
import static play.routing.RoutingDsl.fromComponents;
import static play.server.Server.forRouter;
public class DemoPlayTest {
#Test
public void run() throws InterruptedException {
Server server = forRouter(
9001,
(components) ->
fromComponents(components)
.POST("/echo")
.routeTo(DemoPlayTest::action)
.build());
Thread.sleep(1111111);
}
public static Result action() {
final String body = new String(request().body().asBytes().toArray());
return ok("Gut: " + body + "\n");
}
}
I am trying to launch an initial test of a Vertx.io server, but I get the following error message:
Exception in thread "main" java.lang.NoClassDefFoundError: org/vertx/java/core/Handler
Code:
package com.company;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vertx.java.core.Handler;
import org.vertx.java.core.Vertx;
import org.vertx.java.core.VertxFactory;
import org.vertx.java.core.http.HttpServerRequest;
import java.io.IOException;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
private Object shutdownLock = new Object();
public Main() throws IOException, InterruptedException {
start(1234);
keepServerFromShuttingDown();
}
private void keepServerFromShuttingDown() throws InterruptedException {
synchronized (shutdownLock) {
shutdownLock.wait();
}
log.info("Shutting down");
}
public void start(int port) {
Vertx vertx = VertxFactory.newVertx();
vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() {
#Override
public void handle(HttpServerRequest request) {
}
}).listen(port);
}
public static void main(String[] args) throws IOException, InterruptedException {
new Main();
}
}
pom.xml:
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-platform</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-hazelcast</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
It looks like a basic CLASSPATH issue where it is not able to find Vertx classes while executing your program. Please check if the vertx libraries are indeed a part of your CLASSPATH.
Though unrelated, but if you are checking out Vertx for some new projects, I highly recommend version 3.0 and you could start with this simple maven project example