Behavior driven development with calabash for android

68
Behavior Driven Development with Calabash for Android Teresa Holfeld | Ubilabs

Transcript of Behavior driven development with calabash for android

Behavior Driven Development with

Calabash for AndroidTeresa Holfeld | Ubilabs

CreditsTeresa Holfeld

Head of Mobile @ Ubilabs@TeresaHolfeld

Selim Salman

Android Evangelist Engineer@A_SelimS

Behavior Driven Development

Behavior Driven DevelopmentWe want to do Scrum.

We have a Product Owner who can’t code.

This Product Owner has to write Acceptance Criteria for our tickets.

We have to show them that the Acceptance Criteria are met.

Can we agree on some format that makes it easier for both of us?

Behavior Driven DevelopmentRuby: Cucumber

Language: Gherkin

Behavior Driven DevelopmentRuby: Cucumber

Language: Gherkin Given <some precondition>

When <some action by the actor>

Then <some testable outcome is achieved>

Behavior Driven DevelopmentRuby: Cucumber

Language: Gherkin

Mobile: Calabash

● Implements Cucumber● Uses Gherkin

Given <some precondition>

When <some action by the actor>

Then <some testable outcome is achieved>

Behavior Driven DevelopmentRuby: Cucumber

Language: Gherkin

Mobile: Calabash

● Implements Cucumber● Uses Gherkin

Android: Calabash-android

Given <some precondition>

When <some action by the actor>

Then <some testable outcome is achieved>

Gherkin

Gherkin● Simple Domain Specific Language (DSL) with

natural language constructs

Gherkin● Simple Domain Specific Language (DSL) with

natural language constructs

Given <some precondition>

When <some action by the actor>

Then <some testable outcome is achieved>

Gherkin● Simple Domain Specific Language (DSL) with

natural language constructs

Scenario: Multiple Givens

Given one thing

Given another thing

Given yet another thing

When I open my eyes

Then I see something

Then I don't see something else

Gherkin● Simple Domain Specific Language (DSL) with

natural language constructs

Scenario: Multiple Givens

Given one thing

And another thing

And yet another thing

When I open my eyes

Then I see something

But I don't see something else

Cucumber

CucumberCucumber:

● Software tool for writing automated acceptance tests in BDD● Gherkin: Given - When - Then● Origin: Ruby

CucumberCucumber:

● Software tool for writing automated acceptance tests in BDD● Gherkin: Given - When - Then● Origin: Ruby ● Java, JavaScript, C#, PHP

CucumberKeywords:

● Feature

● Scenario

● Given, When, Then, And, But

● Background

● Scenario Outline

● Examples

Cucumber Feature, ScenarioFeature: Load tracks of the releases of a record label.

Scenario: As a user I want to load all tracks for all records of a given record label.

Given I see the record label “Rivulet Records”

And I see the record “Closed Sessions”

And I see the artist “Various”

When I press “Show all tracks”

And I wait for 3 seconds

Then I see “Sigil Magic, How To Lose Orientation, This Is The Game We Play, So Fi Trance,

Closed Session”

Cucumber BackgroundFeature: Load tracks of the releases of a record label.

Background:

Given I see a search field

When I type “Rivulet Records” into the search field

And I wait for 3 seconds

Then I see “Rivulet Records” # this is the record label

And I see “Closed Sessions” # this is the album

Scenario: As a user I want to load all tracks for all records of a given record label.

Given I see the record label “Rivulet Records”

And I see the record “Closed Sessions”

And I see the artist “Various”

When I press “Show all tracks”

[...]

Cucumber Scenario Outline, Examples Scenario: As a user I want to load all tracks for the record “Closed Sessions” of the label

“Rivulet Records”.

Given I see the record label “Rivulet Records”

And I see the record “Closed Sessions”

When I press “Show all tracks”

Then I see “Sigil Magic, How To Lose Orientation, This Is The Game We Play, So Fi Trance,

Closed Session”

Scenario: As a user I want to load all tracks for the record “Floating Woven” of the label

“Paradise Now”.

Given I see the record label “Paradise Now”

And I see the record “Floating Woven”

When I press “Show all tracks”

Then I see “Gerold Dub, Meridia 02509, Floating Woven”

Cucumber Scenario Outline, Examples Scenario: As a user I want to load all tracks for the record “Closed Sessions” of the label

“Rivulet Records”.

Given I see the record label “Rivulet Records”

And I see the record “Closed Sessions”

When I press “Show all tracks”

Then I see “Sigil Magic, How To Lose Orientation, This Is The Game We Play, So Fi Trance,

Closed Session”

Scenario: As a user I want to load all tracks for the record “Floating Woven” of the label

“Paradise Now”.

Given I see the record label “Paradise Now”

And I see the record “Floating Woven”

When I press “Show all tracks”

Then I see “Gerold Dub, Meridia 02509, Floating Woven”

Cucumber Scenario Outline, Examples Scenario Outline: As a user I want to load all tracks for a given record of a given label.

Given I see the record label <label>

And I see the record <record>

When I press “Show all tracks”

Then I see <tracks>

Examples:

| label | record | tracks |

| Rivulet Records | Closed Sessions | Sigil Magic, [...] |

| Paradise Now | Floating Woven | Gerold Dub, [...] |

https://cucumber.io/docs/reference

Cucumber Step Definitions Scenario: As a user I want to load all tracks for all records of a given record label.

Given I see the record label “Rivulet Records”

Given(/I see the record label “([^”]*)”$/) do |label|

puts “Record label: #{label}”

end

Calabash

Calabash

Calabash

Calabash

Calabash

Calabash:

● Framework for automated acceptance tests for iOS and Android● By Xamarin

Calabash-android:

● Calabash testing framework for Android● Uses Cucumber + Gherkin● Ruby

Calabash

How does it work?

Android app wrapper around Robotium

Exposes view hierarchy as HTML server

Calabash Ruby framework talks to this HTML server

Calabash

Image source: https://anadea.info/blog/introduction-to-calabash

Calabash

Calabashshow_tracks.feature

Calabashcalabash_steps.rb

CalabashCalabash console

CalabashCalabash console

CalabashCalabash console

CalabashCanned steps: steps the framework already implemented for you

Step Definitions: how to define your own steps

Ruby API: what you can use for implementing your own steps

Calabash - Canned StepsCheck if text is there:

Then /^I see "([^\"]*)"$/

Then /^I should see "([^\"]*)"$/

Calabash - Canned StepsCheck if text is there:

Then /^I see "([^\"]*)"$/

Then /^I should see "([^\"]*)"$/

Check if text is not there:

Then /^I should not see "([^\"]*)"$/

Then /^I don't see "([^\"]*)"$/

Calabash - Canned StepsInput actions:

Then /^I toggle checkbox number (\d+)$/ do |index|

Then /^I enter "([^\"]*)" into input field number (\d+)$/ do |text, index|

Calabash - Canned StepsInput actions:

Then /^I toggle checkbox number (\d+)$/ do |index|

Then /^I enter "([^\"]*)" into input field number (\d+)$/ do |text, index|

Touching:

Then /^I press the "([^\"]*)" button$/ do |text|

Then /^I click on screen (\d+)% from the left and (\d+)% from the top$/ do |x, y|

Calabash - Canned StepsInput actions:

Then /^I toggle checkbox number (\d+)$/ do |index|

Then /^I enter "([^\"]*)" into input field number (\d+)$/ do |text, index|

Touching:

Then /^I press the "([^\"]*)" button$/ do |text|

Then /^I click on screen (\d+)% from the left and (\d+)% from the top$/ do |x, y|

Buttons:

Then /^I go back$/

Then /^I press the menu key$/

Calabash - Canned StepsGestures:

Then /^I swipe left$/

Then /^I scroll down$/

Calabash - Canned StepsGestures:

Then /^I swipe left$/

Then /^I scroll down$/

Waiting:

Then /^I wait for (\d+) seconds$/ do |seconds|

Then /^I wait up to (\d+) seconds for "([^\"]*)" to appear$/ do |timeout, text|

Calabash - Step DefinitionsThen(/^I see a map$/) do

map_view = element_exists("MapView")

if not map_view

screenshot_and_raise "No map view found!"

end

end

Calabash - Step DefinitionsSetting a geolocation:

Then(/^I set my location to (\d+)\.(\d+), (\d+)\.(\d+)$/) do |arg1, arg2, arg3, arg4|

lat = "#{arg1}.#{arg2}"

long = "#{arg3}.#{arg4}"

set_gps_coordinates(lat, long)

end

Calabash - Advanced StuffReferencing steps:

Given(/^I checked if notes are empty$/) do

steps %Q{

Given I see the "Notes" button

When I press the "Notes" button

Then I see "No notes."

}

end

Calabash - Advanced StuffRepeating steps:

Given(/^I entered (\d+) note(?:s)?$/) do |n|

for i in 1..n.to_i

steps %Q{

Given I see "New Note"

When I press "New Note"

And I enter "Note #{i}" into the note field

And I press "Save"

Then I see "Note #{i}"

}

end

end

Calabash - Ruby API> query("FrameLayout index:0")

[

[0] {

"id" => "content",

"enabled" => true,

"contentDescription" => nil,

"class" => "android.widget.FrameLayout",

"rect" => {

"center_y" => 617.0,

"center_x" => 384.0,

"height" => 1134,

"y" => 50,

"width" => 768,

"x" => 0

},

"description" => "android.widget.FrameLayout{41f40dc0 V.E..... ........ 0,50-768,1184 #1020002

android:id/content}"

}

]

Calabash - Ruby APIelement_exists(uiquery)

element_does_not_exist(uiquery)

Calabash - Ruby APIelement_exists(uiquery)

element_does_not_exist(uiquery)

wait_for_elements_exist(elements_arr, options={})

wait_for_elements_exist( ["button marked:'OK'", "* marked:'Cancel'"], :timeout => 2)

Calabash - Ruby APIfail(msg)

fail(msg="Error. Check log for details.")

Calabash - Ruby APIfail(msg)

fail(msg="Error. Check log for details.")

screenshot(options={:prefix=>nil, :name=>nil})

screenshot({:prefix => "/tmp", :name => "my.png"})

Calabash - Ruby APIfail(msg)

fail(msg="Error. Check log for details.")

screenshot(options={:prefix=>nil, :name=>nil})

screenshot({:prefix => "/tmp", :name => "my.png"})

screenshot_and_raise(msg, options)

screenshot_and_raise(msg="Error. Check log for details.",

options={:prefix => "/tmp", :name => "error.png"})

Calabash - Documentation and TutorialsCalabash Android GitHub: https://github.com/calabash/calabash-android

Calabash Ruby API: https://github.com/calabash/calabash-android/blob/master/documentation/ruby_api.md

Calabash Developer Site: https://developer.xamarin.com/guides/testcloud/calabash/

Testmunk Documentation and Tutorials: https://testmunk.readthedocs.io/en/latest/

Behavior Driven Development

Alternatives● Cucumber-android + Espresso● Espresso and comments● JBehave● Concordion● JDave● Easyb

Yay or nay?+ Serves as a technical documentation+ Non-tech staff can understand+ Enforces well-defined acceptance criteria+ Easy to run, easy to learn

- Comes with overhead: have to develop steps in Ruby- You have to implement certain things yourself

(e.g. scrolling in RecyclerView)- You need to convince your Product Owner to write acceptance criteria m(

Teresa Holfeld

Head of Mobile @ Ubilabs@TeresaHolfeld

www.ubilabs.net/jobs

And also thank you for listening.Questions welcome!

Calabash - Advanced StuffResuming an Activity:

Then(/^I resume the app$/) do

system("#{default_device.adb_command} shell am start -n

com.example.calabash.MainActivity")

end

Calabash - Canned StepsGestures:

Then /^I swipe left$/

Then /^I swipe right$/

Then /^I scroll down$/

Then /^I scroll up$/

Then /^I select "([^\"]*)" from the menu$/ do |identifier|

Then /^I drag from (\d+):(\d+) to (\d+):(\d+) moving with (\d+) steps$/ do

|from_x, from_y, to_x, to_y, steps|

x:y co-ordinates are expressed as percentages of the screen width:height.

Calabash - Canned StepsWaiting:

Then /^I wait for 1 second$/ # 1 second

Then /^I wait for a second$/ # 1 second

Then /^I wait$/ # 2 seconds

Then /^I wait for (\d+) seconds$/ do |seconds| # specified number of seconds

Calabash - Canned StepsWaiting:

Then /^I wait for 1 second$/ # 1 second

Then /^I wait for a second$/ # 1 second

Then /^I wait$/ # 2 seconds

Then /^I wait for (\d+) seconds$/ do |seconds| # specified number of seconds

Then /^I wait for "([^\"]*)" to appear$/ do |text|

Then /^I wait up to (\d+) seconds for "([^\"]*)" to appear$/ do |timeout, text|

Then /^I wait up to (\d+) seconds to see "([^\"]*)"$/ do |timeout, †ext|