Tuesday, August 30, 2016

Cucumber Automation - Chapter 1


  NOTE: Aim of this page is to get familiar with building a framework from scratch

 

About

Cucumber is an automated tool for running automated tests, mostly used in Behaviour-Driven Development (BDD). Cucumber brings test documentation and specifications together. Hence it is always considered as an up to date document for reference of application under development.

NOTE: Cucumber supports different software platforms.

Cucumber Environment Setup

In this section I will guide you with basic details required for setting up eclipse with cucumber, by which one should be able to start practicing from scratch.

Downloads

1. Download latest version of eclipse or the version you are familiar with from here i.e. https://eclipse.org/

2. Download required JAR's. Below are links and name of the JAR files which we will download and save in a folder .

http://repo1.maven.org/maven2/info/cukes/





http://mvnrepository.com/  (Hamcrest, junit)



http://www.seleniumhq.org/download/


List of required Jar's.



 NOTE: Above were the latest versions available while writing this article.

3. Install eclipse

Summarize our actions:
  1. We will be using JAVA to write our test code.
  2. IDE - We will be using Eclipse (Those familiar with IntelliJ or other IDE can proceed with same).
  3. We will use Selenium to perform browser actions like say, 'Click button', 'Insert text' etc
  4. We will use Cucumber-jvm for writing test scenarios and
  5. Finally JUnit for asserting etc.

-----------------------------------------------------------------------------------------------------------

Create Project

Open Eclipse and create a new JAVA project (File > New > Java Project). Name the project to say, 'CucumberAutoPractice'.


A folder structure as shown below will be created.



The next step will be to add the JAR's which we have downloaded to the Library. Right click on the project and select properties.

Select 'Java Build Path' as shown below.


Click on 'Add external JAR's'. Browse and navigate to the folder where in we have saved the downloaded JAR's. Select all files and proceed. Click on OK and we should now be able to see 'Referenced Libraries' in the project structure as shown below.


-----------------------------------------------------------------------------------------------------------

Create a Runner Class

Right click on the 'src' directory and create a new package. Name it to say, 'cucumber'. 


Right click on this package and create a new class and name it to say, 'RunnerClass'. A java file will be created as shown below.



Add below piece of code in the RunnerClass.java file.

    @RunWith(Cucumber.class)
    @CucumberOptions (features = "src/featureFiles/")
    public class RunFeatures {
    }   

One should now see errors like '...cannot be resolved to a type'. To resolve this issue we will have to import few things. Hit Ctrl+Shift+O (Eclipse) to import the libraries (highlighted in red below) and one should now be able to see an error free 'RunnerClass'.

----
package cucumber;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

public class RunnerClass {
   
    @RunWith(Cucumber.class)
    @CucumberOptions (features = "src/featureFiles/")
    public class RunFeatures {
    }   

}
----

This 'RunnerClass' is required to run Cucumber. Notice in this 'RunnerClass.java' we are only adding annotations and not any code.

@RunWith annotation tells JUnit that tests should run using cucumber class present in package which has been imported. 

@CucubmerOptions is like a property file or setting.  There are different options like features, glue, plugin, dryrun etc which we will discuss as the we proceed.

In the above 'RunnerClass' we are using option features and associating path of the folder where we have placed all our feature files.

What are feature files? A feature file can contain one or more scenario's and is an important part of cucumber. We can have n number of feature files for example,
  • Loginfeature.file - which will have login scenarios
  • Profilefeature.file - which may have scenario related to personal details
-----------------------------------------------------------------------------------------------------------

Create Feature File

Create a new package under 'src' and name it say, 'featureFiles'. This will be the location wherein we will be saving our feature files. 

Right click on this package and create a new file


Name the file say, 'MyFirstFeatureFile.feature'. Notice here along with the file name we are also providing file extension i.e. (*.feature).


Once the feature file is created, we should now be able to see some default texts as shown below.


Understanding the feature file content. 

From the default text generated we will pick one of the scenario, modify it and try to understand the same.

Feature: Login page
Scenario: Registered user is able to login with valid credentials
Given User is on the login page
  And User inserts valid username
  And User inserts valid password
When User clicks on submit button
Then User is logged in
  And User is on homepage


Important:
Colon (:) is only used with Feature and Scenario. DO NOT use colon (:) character in your steps.

Now we have 2 files,
1. RunnerClass.java
2. MyFirstFeatureFile.feature


-----------------------------------------------------------------------------------------------------------
Before we execute or run this feature file, we shall now try to understand the language in which the feature file is written. As seen in above example we are providing some specifications in plain English. This language is know as GHERKIN.

Below are few of the keywords used in GHERKIN language.
  • Feature
  • Scenario
  • Scenario outline
  • Given, When, Then, And, But (These are also know as Steps)
Feature: We can feature is something like a title of a document/article by name of which itself one understands what it covers. As in our example (MyFirstFeatureFile.feature), here the feature is 'Login page' or say 'Login'. Under which we will have different scenario's like - Valid login, Invalid login etc

Scenario: As in our example we are considering feature - Login page. So the scenario's which we will be adding under this feature should only be related to 'Login page'.
 E.g:
  • User is able to login with valid credentials.
  • User is not able to login with invalid username.
  • User is not able to login with invalid password.
  • User is not able to login with invalid username and password etc.
Scenario Outline: (Is discussed further down)

For now we have got a good amount of idea about contents of feature file and Gherkin language. So now we will proceed executing the feature file in eclipse.

Feature: Contains one or more Scenario's and defines which feature you will be testing
Scenario's: Contains one or more Steps
Given: Precondition of the test
And: Additional steps being performed in tests.
Then: Final result of the test (Expected result)
 -------------------------------------------------------------------------------------

Run or Execute the feature file.

Let us go back to Eclipse. Right click on the feature file and select option 'Run as' > 'Cucumber Feature' or Click on the 'Play' icon.


What happens when we run or execute the feature file.
  1. RunnerClass.java file is triggered. It navigates to the folder where '*.feature' files are placed.
  2. Locates the feature file.
  3. Finds the scenario's within this feature file.
  4. Executes steps mentioned in the scenario one by one. Once steps for scenario 1 is executed it moves to the next scenario and executes it in the same manner.
 Once the feature is executed, the output is displayed in the console as shown below.

-- Console output --

Feature: Login page

  Scenario: Registered user is able to login with valid credentials # D:/WS/Selenium/CucumberAutoPractice/src/featureFiles/MyFirstFeatureFile.feature:2
    Given User is on the login page
    And User inserts valid username
    And User inserts valid password
    When User clicks on submit button
    Then User is logged in
    And User is on homepage

1 Scenarios (1 undefined)
6 Steps (6 undefined)
0m0.000s


You can implement missing steps with the snippets below:

@Given("^User is on the login page$")
public void user_is_on_the_login_page() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}


@Given("^User inserts valid username$")
public void user_inserts_valid_username() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}


@Given("^User inserts valid password$")
public void user_inserts_valid_password() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}


@When("^User clicks on submit button$")
public void user_clicks_on_submit_button() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}


@Then("^User is logged in$")
public void user_is_logged_in() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}


@Then("^User is on homepage$")
public void user_is_on_homepage() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}


-- Console output --

Decode the results/console output

1 Scenarios (1 undefined)
6 Steps (6 undefined)
0m0.000s

1 Scenario was found and it had 6 Steps but both were undefined. It was able to find Scenario, Steps but code (glue) was missing. Hence in the console we find a suggestion which says, 'You can implement missing steps with the snippets (code/glue) below'.

Now if we try to recall, in Eclipse we see warnings in the feature file which says, 'Step.... does not have a matching glue'. 



 In the next section we will try to write a matching glue code and try executing it.
-----------------------------------------------------------------------------------------------

 Steps to write a 'glue code'.

  • Create a new package say, 'cucumberSteps'. 
  • Create a new class file and name it 'StepsForMyFirstFeature.java'. 
  • Copy the snippet and paste it in this new class file.
  • Import the libraries (Ctrl+Shift+O) 
  • Save the changes
  
-- Code --
package cucumberSteps;

import cucumber.api.PendingException;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class StepsForMyFirstFeature {
   
    @Given("^User is on the login page$")
    public void user_is_on_the_login_page() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @Given("^User inserts valid username$")
    public void user_inserts_valid_username() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @Given("^User inserts valid password$")
    public void user_inserts_valid_password() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @When("^User clicks on submit button$")
    public void user_clicks_on_submit_button() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @Then("^User is logged in$")
    public void user_is_logged_in() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }

    @Then("^User is on homepage$")
    public void user_is_on_homepage() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }   

}

 
-- Code --

IMPORTANT: While manually writing the steps, we have to ensure that the text used in step definition for e.g. @Given should be same as in the step of feature file as these are case sensitive. Below screenshot will illustrate the same.


    
Go back to the feature file and run it. We should see the output as below which says, Pending exception was thrown.

1 Scenarios (1 pending)
6 Steps (5 skipped, 1 pending)
0m0.095s
What happened here is, cucumber was able to find 1 Scenario, it also found an step but this step wasn't implemented hence 'Pending exception' was thrown. Also as it could not execute step 1 it has skipped the remaining steps.

Now to make our 'StepsForMyFirstFeature.java' more simpler. We will remove the pending exception and replace '// Write code here that turns the phrase above into concrete actions' with simple 'System.out.println("Put your text here");'

For example:

    @Given("^User is on the login page$")
    public void user_is_on_the_login_page() throws Throwable {
        // Write code here that turns the phrase above into concrete actions
        throw new PendingException();
    }


will be replaced by

    @Given("^User is on the login page$")
    public void user_is_on_the_login_page() throws Throwable {
        System.out.println("user is able to see the login page");
    }
 


Make the changes to all steps and save the changes. Run the feature file again. Output will be as shown below.



1 Scenarios (1 passed)
6 Steps (6 passed)
0m0.100s


Step by step execution:
1. Feature 'Login page' was found
2. Scenario 'Registered user is able to login with valid credentials' was identified and executed.
3. Each step under above Scenario was executed without error.
4. Overall result - Passed


Revision:

1. IDE was installed.
2. Required files were downloaded and configured.
3. Folder structure was created in IDE
4. RunnerClass was created
5. Feature file was created
6. Finally tests was run through IDE

-----------------------------------------------------------------------------------------------------------------

Q & A

Q: Can we add more than one scenario in a feature?
A: Yes, we can add more than one scenario in a feature and run it. We will take the same login example and proceed.

Feature: Login page
Scenario: User is able to login with valid credentials
Given User is on the login page
  And User inserts valid username
  And User inserts valid password
When User clicks on submit button
Then User is logged in
  And User is on homepage

Scenario: User is not able to login with invalid username
Given User is on the login page
  And User inserts invalid username
  And User inserts valid password
When User clicks on submit button
Then User is logged in
  And User is on homepage

Scenario: User is not able to login with invalid password
Given User is on the login page
  And User inserts valid username
  And User inserts invalid password
When User clicks on submit button
Then User is logged in
  And User is on homepage
-------------------------------------------------------------------
Q: In the feature file we are using Given, When, Then & And in steps. But in the step definitions some And's are converted to Given while others to When. Why is that?
A: Yes, for some reason when And step is used after Given it will be automatically converted to Given. Similarly if And step is used after When/Then it will be automatically converted to When/Then respectively. This will not impact or cause any issue when the feature is run. However we can manually update respective values to And, refer below question for more details.

FeatureFile:
Given User is on the login page
  And User inserts valid username
  And User inserts valid password
When User clicks on submit button
Then User is logged in
  And User is on homepage

StepDefinition:
@Given("^User is on the login page$")
@Given("^User inserts valid username$")
@Given("^User inserts valid password$")
@When("^User clicks on submit button$")
@Then("^User is logged in$")
@Then("^User is on homepage$")

 -------------------------------------------------------------------
Q: Can I still go with the traditional way and still use And in Step definitions?
A: Yes, we can still use And provided we also import it's library i.e.
import cucumber.api.java.en.And; 

 -------------------------------------------------------------------



No comments:

Post a Comment