Monday, December 28, 2015

Cucumber Hooks/TestRunner(Glue Code)

Glue Code is the code that interacts directly with your application. There are two kinds of Glue code – Step Definitions and Hooks.

Cucumber provides a number of hooks which allow us to run blocks at various points in the Cucumber test cycle. You can put them in your support/env.java file or any other file under the support directory, for example in a file called support/hooks.java. There is no association between where the hook is defined and which scenario/step it is run for, but you can use tagged hooks (see below) if you want more fine grained control.

All defined hooks are run whenever the relevant event occurs


Hooks.java look like,


package com.shasta.StepDefinitions;
import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;



@RunWith(Cucumber.class)
@CucumberOptions(
features = {"resource/"},
plugin = {"pretty", "html:target/cucumber-html-report","json:target/cucumber.json"},
tags = {"@login,@testing,@closeBrowser"}
  )

public class HooksFile{
}


Scenario hooks

  • Before hooks will be run before the first step of each scenario. They will run in the same order of which they are registered.


/*@Before
public void setUp() throws Exception{
# Do something before each scenario. 
}

# The +scenario+ argument is optional, but if you use it, you can get the title, # description, or name (title + description) of the scenario that is about to be # executed.

  • After hooks will be run after the last step of each scenario, even when there are failing, undefined, pending or skipped steps. They will run in the opposite order of which they are registered.
@After
public void tearDown() throws Exception{
closeBrowser(driver);
}
 # Do something after each scenario. # The +scenario+ argument is optional, but # if you use it, you can inspect status with # the #failed?, #passed? and #exception methods.

  • Around hooks will run "around" a scenario. This can be used to wrap the execution of a scenario in a block. The Around hook receives a scenario object and a block (Proc) object. The scenario will be executed when you invoke block.call.
Tagged hooks

Sometimes you may want a certain hook to run only for certain scenarios. This can be achieved by associating a Before, After, Around or AfterStep hook with one or more tags. You can OR and AND tags in much the same way as you can when running Cucumber from the command line. 
Think twice before you use this feature, as whatever happens in hooks is invisible to people who only read the features. You should consider using background as a more explicit alternative if the setup should be readable by non-technical people.

Global hooks


If you want something to happen once before any scenario is run - just put that code at the top-level in your env.java file (or any other file in your features/support directory.

AfterConfiguration
You may also provide an AfterConfiguration hook that will be run after Cucumber has been configured. 

Writing Global methods

            The methods needed to map steps to actual Java code may be implemented in many step definition files. All step methods are global and visible to Cucumber. This means that the functionality needed may be implemented in more than one class. Global functions may feel horrible but there is an cunning idea behind having them global. If you describe your system using the exact same words and mean two different areas of your system, you have a larger problem than global methods. You will need to address this so parts that does different things in your system actually is described differently.

sample step definition and global methods are,


package com.shasta.bdd.steps;
import com.shasta.bdd.calculator.Calculator;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class CalculatorSteps {
    private Calculator calculator;
    @Before
    public void setUp() {
        calculator = new Calculator();
    }
    @Given("^I have a calculator$")
    public void i_have_a_calculator() throws Throwable {
        assertNotNull(calculator);
    }
    @When("^I add (\\d+) and (\\d+)$")
    public void i_add_and(int arg1, int arg2) throws Throwable {
        calculator.add(arg1, arg2);
    }
    @Then("^the result should be (\\d+)$")
    public void the_result_should_be(int result) throws Throwable {
        assertEquals(result, calculator.getResult());
    }


And the Calculator itself to satisfy the tests

package com.shasta.bdd.calculator;
public class Calculator {
    private int result;
    public void add(int arg1, int arg2) {
        result = arg1 + arg2;
    }
    public int getResult() {
        return result;
    }
}