Where do Before and After hooks go in Cucumber - testing

I have a fairly simple Cucumber test framework with a feature file, a step definitions file, and a test runner class that looks like this:
#RunWith(Cucumber.class)
#CucumberOptions(features = "src/test/java/com/tests/cucumber/features/ui/ExampleTest.feature",
glue = { "com.tests.cucumber.stepdefinitions" },
)
public class ExampleTestRunner {
}
This runs a scenario in the feature file just fine. Now I want to add a Before and After hook to do some setup and teardown, but I can't for the like of me get the hooks to run. I've tried adding the hooks to the ExampleTestRunner and to the StepDefinition class, but they never run. Where should I put these hooks? At the moment, the hooks just look like this, but I'll add content to them once I've worked this out!
package com.tests.cucumber.stepdefinitions;
import cucumber.api.java.After;
import cucumber.api.java.Before;
public class StepDefinitions {
#Before
public void before() {
System.out.println("starting before()");
}
}
Thanks for any help.

I am a little hesitant to answer this question even though I managed to get this to work. As far as I can tell, the problem was that I had added the Before and After methods in classes that were extended by other classes. In this situation, the tests would not run. I had to add the Before and After methods to a class that was not extended.
It feels like this is similar to the situation in which if you specify a step definition in a class that is extended by another class, then the step definition is considered to have a duplicate definition. Do I have the correct diagnosis here?

I use like this;
Runner Class:
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src\\test\\features\\ui_features"},
glue = {"com\\base\\tm\\auto_reg\\tests\\ui_tests\\price_features"},
plugin = {"com.cucumber.listener.ExtentCucumberFormatter:"}
)
public class PriceFeatureRunner {
#BeforeClass
public static void setup() {
RunnerUtil.setup(PriceFeatureRunner.class);
}
#AfterClass
public static void teardown() {
RunnerUtil.teardown();
}
}
RunnerUtil.java:
public class RunnerUtil {
public static void setup(Class<?> clazz) {
String reportPath = "target/cucumber-reports/" + clazz.getSimpleName().split("_")[0] + "_report.html";
ExtentProperties extentProperties = ExtentProperties.INSTANCE;
extentProperties.setReportPath(reportPath);
}
public static void teardown() {
UiHooks uiHooks = new UiHooks();
uiHooks.afterScenario();
ExtentReportConfiguration.configureExtentReportTeardown();
}
}
UiHooks.java
public class UiHooks implements HookHelper {
public static final String BASE_URL = "https://www.stackoverfow.com/";
private Scenario scenario;
#Override
#Before
public void beforeScenario(Scenario scenario) {
this.scenario = scenario;
Reporter.assignAuthor(System.getProperty("user.name"));
}
#Override
#After
public void afterScenario() {
if (HookUtil.driver != null) {
HookUtil.driver.quit();
}
if (HookUtil.seleniumBase != null) {
HookUtil.seleniumBase.stopService();
}
}
#Override
#After
public void afterTest() {
if (HookUtil.driver != null) {
HookUtil.driver.quit();
}
if (HookUtil.seleniumBase != null) {
HookUtil.seleniumBase.stopService();
}
}
}
HookHelper.Java
public interface HookHelper {
#Before
void beforeScenario(Scenario scenario);
#After
void afterScenario();
void afterTest();
}

Related

How to attach/embed captured screenshots during custom softAssertion into Cucumber Report?

In soft assertion screenshot get captured when softAssertions.assertAll() is called. So to capture screenshots for each soft Assertion failure, created simple CustomAssertion which extends to SoftAssertions and in that override a method name onAssertionErrorCollected().
Below is the sample code.
public class CustomSoftAssertion extends SoftAssertions {
public CustomSoftAssertion() {
}
#Override
public void onAssertionErrorCollected(AssertionError assertionError) {
File file = TestRunner.appiumDriver.getScreenshotAs(OutputType.FILE);
try {
FileUtils.copyFile(file, new File(System.getProperty("user.dir") + File.separator + "ScreenShots" + File.separator + LocalDate.now().format(DateTimeFormatter.ofPattern("MMMM_dd_yyyy")) + File.separator + "demo.png"), true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
In the step definition file:
CustomSoftAssertion softAssertion = new CustomSoftAssertion();
softAssertion.assertThat(isLogin).isTrue();
Above code is working properly. But, how to this captured attach/embed this screenshots into the cucumber report?
Note: For Assertion I am using Assertj library.
You attach scenarios to the report by using scenario.attach. This means you'll have to setup some plumbing to get the scenario into the assertion.
public class CustomSoftAssertion extends SoftAssertions {
private final Scenario scenario;
public CustomSoftAssertion(Scenario scenario) {
this.scenario = scenario;
}
#Override
public void onAssertionErrorCollected(AssertionError assertionError) {
// take screenshot and use the scenario object to attach it to the report
scenario.attach(....)
}
}
private CustomSoftAssertion softAssertion;
#Before
public void setup(Scenario scenario){
softAssertion = new CustomSoftAssertion(scenario);
}
#After // Or #AfterStep
public void assertAll(){
softAssertion.assertAll();
}
#Given("example")
public void example(){
softAssertion.assertThat(isLogin).isTrue();
}

Getting noBaseStepListener error while using Serenity RestAssured

I am trying to implement Rest Assured framework with cucumber
I am facing a weird scenario that I have defined all my step definitions of my feature file then also I am getting error as below when I run my feature file:-
Step undefined
You can implement this step and 3 other step(s) using the snippet(s) below:
#Given("I create new service by using create service API data")
public void i_create_new_service_by_using_create_service_api_data() {
// Write code here that turns the phrase above into concrete actions
throw new io.cucumber.java.PendingException();
}
and When I run the same from Junit Testrunner then I get error as below :-
INFO net.serenitybdd.rest.decorators.request.RequestSpecificationDecorated - No BaseStepListener, POST /services not registered.
In my framework I am defining basepackage containing base class file which is as below :-
public class TestBase {
public static Properties propertyConfig = new Properties();
public static FileInputStream fis;
public static Response response;
public static RequestSpecification requestSpecification;
public static void loadPreConfigs(){
try {
fis = new FileInputStream("./src/test/resources/ConfigurationURLs/config.properties");
try {
propertyConfig.load(fis);
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
RestAssured.baseURI=propertyConfig.getProperty("BaseURI");
}
}
Then I have a ApiCall package which contains all class files which have request specification and respective response storing rest API calls
The APICall file is given below:-
public class PostRequestCall extends TestBase {
private static String productVal;
public static int getProductVal() {
return Integer.parseInt(productVal);
}
public static void setProductVal(String productVal) {
PostRequestCall.productVal= productVal;
}
public RequestSpecification definePostRequest(){
requestSpecification= SerenityRest.given();
requestSpecification.contentType(ContentType.JSON);
return requestSpecification;
}
public Response CreateService(String serviceName){
JSONObject jsonObject=new JSONObject();
jsonObject.put("name",serviceName);
response=definePostRequest().body(jsonObject).post(propertyConfig.getProperty("createService"));
return response;
}
}
Then I have step file which are the class file in which I define the steps of serenity given below:
public class PostRequestSteps {
PostRequestCall postRequestCall=new PostRequestCall();
#Step
public RequestSpecification setPostSpecification(){
TestBase.requestSpecification=postRequestCall.definePostRequest();
return TestBase.requestSpecification;
}
#Step
public Response setPostRequestCall(String serviceName){
TestBase.response=postRequestCall.CreateService(serviceName);
return TestBase.response;
}
}
And I have defined a package which contains all the step definition classes one such class is as below :-
public class PostRequest_StepDefinitions {
String serviceID;
#Steps
PostRequestSteps postRequestSteps=new PostRequestSteps();
#Before
public void setUp() {
TestBase.loadPreConfigs();
}
#Given("I create new service by using create service API data")
public void i_create_new_service_by_using_create_service_api_data() {
postRequestSteps.setPostSpecification();
}
#When("I provide valid name {string} for service creation")
public void i_provide_valid_name_for_service_creation(String serviceName) {
TestBase.response=postRequestSteps.setPostRequestCall(serviceName);
}
#And("I save the id of created service")
public void i_save_the_id_of_created_service() {
serviceID=TestBase.response.jsonPath().get("id").toString();
PostRequestCall.setProductVal(serviceID);
}
#Then("I validate status code {int}")
public void i_validate_status_code(int statusCode) {
Assert.assertEquals(TestBase.response.getStatusCode(),statusCode);
}
The Junit Runner file and feature files are below

How to run a TestNG class from another class

Hi When i run the following testNG file as a standalone script if executes as expected.
public class TESTTNGClass {
WebDriver driver;
#Test
public void f() {
System.out.println("In Test");
}
#BeforeMethod
public void beforeMethod() {
System.out.println("Before Test");
}
#AfterMethod
public void afterMethod() {
System.out.println("After Test");
}
}
O/P:
Before Test
In Test
After Test
But why does the same not work when called from another class. Please help to achieve the same when triggered from another class. Following is the class calling the test class
public class TESTClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
TESTTNGClass t = new TESTTNGClass();
t.f();
}
}
O/P:
In Test
Here is the Answer to your Question:
In the process of understanding and experiment with Java & TestNG you have diminished the Annotation power of TestNG.
When you are executing TESTTNGClass.java as a TestNG Test all works well. No issues.
When you are executing TESTClass.java as a Java Application, Java only understands main() where you are creating an object of Class TESTTNGClass and then you are calling the method f(). As Java Compiler have have no idea of BeforeMethod, Test & AfterMethod Annotations of TestNG, it simply executes f() method, prints In Test and ends execution.
About how to do it:
Replace main() by some other name foo().
Bring f() from "TESTTNGClass" class into "TESTClass" class.
While you write "TESTClass" class extend "TESTTNGClass" class.
Execute "TESTClass.java" as a TestNG Test
Your Application will look like:
TESTTNGClass Class:
package Q44240531_TestNG_Main;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
public class TESTTNGClass
{
#BeforeMethod
public void beforeMethod() {
System.out.println("Before Test");
}
#AfterMethod
public void afterMethod() {
System.out.println("After Test");
}
}
TESTClass Class:
package Q44240531_TestNG_Main;
import org.testng.annotations.Test;
public class TESTClass extends TESTTNGClass {
#Test
public void f()
{
System.out.println("In Test");
}
}
Let me know if this Answers your Question.
public class TESTClass extends TESTTNGClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
TESTTNGClass t = new TESTTNGClass();
try{
t.f();
}catch (Exception e){
e.printStackTrace();
}
}
}

SpecFlow + Selenium-WebDriver: Sharing a WebDriver Across Steps?

Say I have a scenario that uses steps that are contained in two different classes. Is there a way for both of them to have a handle to the same IWebDriver instance without going through ScenarioContext.Current["webdriverVariableName"]?
That's so ugly. Is there a cleaner way?
I was going to make a class with a public static IWebDriver property that gets assigned at the start of every scenario, so that all my steps could refer to it, but I don't think that will work when I start to run them in parallel, as each scenario would overwrite the global driver.
Specflow offers a Dependency Injection mecanism, so you could get your web driver instance injected in your steps.
See https://github.com/techtalk/SpecFlow/wiki/Context-Injection
See the "Avanced options" section.
I have just started using Specflow but this appears to work;
Create a class which takes IObjectContainer as a constructor and has a BeforScenario method to create the WebDriver instance;
[Binding]
public class WebDriverSupport
{
private readonly IObjectContainer _objectContainer;
public WebDriverSupport(IObjectContainer objectContainer)
{
_objectContainer = objectContainer;
}
[BeforeScenario]
public void InitializeWebDriver()
{
var webDriver = DriverFactory.CreateDriver();
_objectContainer.RegisterInstanceAs<RemoteWebDriver>(webDriver);
}
}
Create your step classes with a constructor which take RemoteWebDriver;
[Binding]
public class POCSteps
{
private readonly IdlWebDriver _driver;
public POCSteps(IdlWebDriver driver)
{
_driver = driver;
}
}
Your steps steps will now have access to a fully instantiated WebDriver object
My tests, which are currently working fine running multithreaded webdriver instances, are using a base step definitions class to hold the driver instance. All step definitions inherit from this, so the driver is available to all steps..
namespace Project.StepDefinitions
{
[Binding]
public class BaseStepDefinitions
{
private const string CurrentPageKey = "Current.Page";
public static IWebDriver Driver { get; set; }
protected LogonPageModel LogonPage
{
get { return (LogonPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
protected RegisterPageModel RegisterPage
{
get { return (RegisterPageModel)ScenarioContext.Current[CurrentPageKey]; }
set { ScenarioContext.Current[CurrentPageKey] = value; }
}
}
}
//////////////
namespace SpecDriver.StepDefinitions
{
[Binding]
public class LoginSteps : BaseStepDefinitions
{
[Given(#"I navigate to the homepage")]
public void GivenINavigateToTheHomepage()
{
Driver.Navigate().GoToUrl(SettingsManager.BaseUrl);
}
}
}
etc etc...
Just create a new separated class with a static property that returns driver:
static class DriverProvider
{
private static IWebDriver _driver;
public static IWebDriver Driver
{
get
{
if (_driver == null)
{
_driver = new ChromeDriver();
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(40);
_driver.Manage().Window.Maximize();
}
return _driver;
}
}
}
Each time you will need to do something with driver, just call it in a such way:
SomeMethod(DriverProvider.Driver);
//
IWebelement e = DriverProvider.Driver.FindElement(By.XPath("you_XPath"));
e.Click();
// etc etc etc

JUnit: Is there a RunListener method, which is called after #After annotated method?

Is there a way to invoke a method after all #After annotated methods of a test method had been run?
I need this for a special framework for my company.
In testng i can use the afterInvocation method, which is called after every configuration method. Is there some alternative in JUnit?
A rule will run after all the #Afters. The ExternalResource could be abused in order to do what you want:
public class VerifyTest {
#Rule public ExternalResource externalResource = new ExternalResource() {
public void after() {
System.out.println("ExternalResource.after");
}
};
#After
public void after1() {
System.out.println("after1");
}
#After
public void after2() {
System.out.println("after2");
}
#Test
public void testVerify throws IOException {
}
}