├── .ruby-version
├── Gemfile
├── features
├── support
│ ├── env.rb
│ ├── hooks.rb
│ ├── start_app.rb
│ └── appium_custom.rb
├── step_definitions
│ ├── screen
│ │ ├── display_message_sreen.rb
│ │ └── main_screen.rb
│ └── play_steps.rb
├── demonstrate.feature
└── play.feature
├── AndroidTestApp
├── ic_launcher-web.png
├── libs
│ └── android-support-v4.jar
├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ │ └── ic_launcher.png
│ ├── values-sw600dp
│ │ └── dimens.xml
│ ├── values
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── menu
│ │ ├── main.xml
│ │ └── display_message.xml
│ ├── values-sw720dp-land
│ │ └── dimens.xml
│ ├── values-v11
│ │ └── styles.xml
│ ├── values-v14
│ │ └── styles.xml
│ └── layout
│ │ ├── activity_display_message.xml
│ │ └── activity_main.xml
├── proguard-project.txt
├── src
│ └── com
│ │ └── example
│ │ └── androidtestapp
│ │ ├── MainActivity.java
│ │ └── DisplayMessageActivity.java
└── AndroidManifest.xml
└── README.md
/.ruby-version:
--------------------------------------------------------------------------------
1 | 1.9.3-p362
2 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'selenium-webdriver', '2.35.1'
4 | gem 'cucumber', '1.3.8'
5 |
--------------------------------------------------------------------------------
/features/support/env.rb:
--------------------------------------------------------------------------------
1 | require "selenium-webdriver"
2 |
3 | $wait = Selenium::WebDriver::Wait.new(:timeout => 30)
4 |
5 |
--------------------------------------------------------------------------------
/AndroidTestApp/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesbarker/cucumber-appium-android/HEAD/AndroidTestApp/ic_launcher-web.png
--------------------------------------------------------------------------------
/AndroidTestApp/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesbarker/cucumber-appium-android/HEAD/AndroidTestApp/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/AndroidTestApp/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesbarker/cucumber-appium-android/HEAD/AndroidTestApp/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidTestApp/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesbarker/cucumber-appium-android/HEAD/AndroidTestApp/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidTestApp/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesbarker/cucumber-appium-android/HEAD/AndroidTestApp/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/AndroidTestApp/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jamesbarker/cucumber-appium-android/HEAD/AndroidTestApp/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/features/support/hooks.rb:
--------------------------------------------------------------------------------
1 | Before do
2 | $driver ||= start_app
3 |
4 | $wait.until {
5 | main_screen_present?
6 | }
7 |
8 | end
9 |
10 | After do
11 | $driver.quit
12 | $driver=nil
13 | end
14 |
--------------------------------------------------------------------------------
/features/step_definitions/screen/display_message_sreen.rb:
--------------------------------------------------------------------------------
1 | def display_screen_visit
2 | #todo
3 | end
4 |
5 | def display_screen_present?
6 | id_text('android:id/action_bar_title') == 'DisplayMessageActivity'
7 | end
8 |
9 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/menu/display_message.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/features/step_definitions/screen/main_screen.rb:
--------------------------------------------------------------------------------
1 | def main_screen_visit
2 | $wait.until { main_screen_present? }
3 | end
4 |
5 | def main_screen_present?
6 | button_exists? 'Send'
7 | end
8 |
9 | def main_screen_click_send_button
10 | click_button 'Send'
11 | end
12 |
13 | def main_screen_message message
14 | fill_in 'com.example.androidtestapp:id/edit_message', message
15 | end
16 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/features/demonstrate.feature:
--------------------------------------------------------------------------------
1 | Feature: Demonstrate
2 | As a BDD tester
3 | I want an automated Android mobile BDD testing framework
4 | So I can streamline my development process
5 |
6 | Scenario: Welcome Message
7 | Given I am on the "Main" screen
8 | And I enter text "Hello World!"
9 | When I click the "Send" button
10 | Then I am taken to the "Display Message" screen
11 | And the message "Hello World!" is displayed
12 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Android Test App
5 | Enter a message
6 | Send
7 | Settings
8 | MainActivity
9 | DisplayMessageActivity
10 |
11 |
--------------------------------------------------------------------------------
/features/step_definitions/play_steps.rb:
--------------------------------------------------------------------------------
1 | Given(/^I am on the "Main" screen$/) do
2 | main_screen_visit
3 | end
4 |
5 | Given(/^I enter text "(.*?)"$/) do |message|
6 | main_screen_message message
7 | end
8 |
9 | When(/^I click the "Send" button$/) do
10 | main_screen_click_send_button
11 | end
12 |
13 | When(/^I click the "Send" button without a message$/) do
14 | main_screen_click_send_button
15 | end
16 |
17 | Then(/^I am taken to the "Display Message" screen$/) do
18 | display_screen_present?
19 | end
20 |
21 | Then(/^the message "(.*?)" is displayed$/) do |message|
22 | text_exists? message
23 | end
24 |
25 |
--------------------------------------------------------------------------------
/features/play.feature:
--------------------------------------------------------------------------------
1 | Feature: Play Around
2 | As a BDD tester
3 | I want an example of Cucumber working with Android and Appium
4 | So I can see if it is a feasible framework for my own project
5 |
6 | Scenario: No Message
7 | Given I am on the "Main" screen
8 | When I click the "Send" button without a message
9 | Then I am taken to the "Display Message" screen
10 | And the message "No Message!" is displayed
11 |
12 | Scenario: Special Characters
13 | Given I am on the "Main" screen
14 | And I enter text "$Hello & Welcome!!"
15 | When I click the "Send" button
16 | Then I am taken to the "Display Message" screen
17 | And the message "$Hello & Welcome!!" is displayed
18 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/layout/activity_display_message.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/features/support/start_app.rb:
--------------------------------------------------------------------------------
1 | def start_app
2 | def capabilities
3 | {
4 | "device" => "Android",
5 | "browserName" => "",
6 | "version" => "4.3",
7 | "app" => "#{Dir.pwd}/AndroidTestApp/bin/MainActivity-debug.apk",
8 | "app-package" => "com.example.androidtestapp",
9 | "app-activity" => "com.example.androidtestapp.MainActivity"
10 | }
11 | end
12 |
13 | http_client = ::Selenium::WebDriver::Remote::Http::Default.new
14 | http_client.timeout = 80
15 |
16 |
17 | Selenium::WebDriver.for(
18 | :remote,
19 | :desired_capabilities => capabilities,
20 | :url => 'http://127.0.0.1:4723/wd/hub',
21 | :http_client => http_client
22 | )
23 | end
--------------------------------------------------------------------------------
/AndroidTestApp/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/AndroidTestApp/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/AndroidTestApp/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/AndroidTestApp/src/com/example/androidtestapp/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.androidtestapp;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.Menu;
7 | import android.view.View;
8 | import android.widget.EditText;
9 |
10 | public class MainActivity extends Activity {
11 | public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.activity_main);
17 | }
18 |
19 | @Override
20 | public boolean onCreateOptionsMenu(Menu menu) {
21 | // Inflate the menu; this adds items to the action bar if it is present.
22 | getMenuInflater().inflate(R.menu.main, menu);
23 | return true;
24 | }
25 |
26 | public void sendMessage(View view) {
27 | Intent intent = new Intent(this, DisplayMessageActivity.class);
28 | EditText editText = (EditText) findViewById(R.id.edit_message);
29 | String message = editText.getText().toString();
30 | intent.putExtra(EXTRA_MESSAGE, message);
31 | startActivity(intent);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Cucumber Appium Android Example ##
2 |
3 | This project demonstrates BDD tests automated on an Android device powered by Cucumber and Appium
4 |
5 | This project comes with:
6 | * a test app (based on Google's Android Tutorial http://developer.android.com/training/index.html)
7 | * example feature files
8 |
9 | Prerequisites: (This has been tested on the following system)
10 | * Mac OSX 10.8.5
11 | * with $ANDROID_HOME environment variable set pointing to your android SDK
12 | * Java 1.6
13 | * Android SDK 22.2.1
14 | * Ant Version 1.8.4
15 | * adb 1.0.31
16 | * Ruby 1.9.3
17 | * with bundler gem (gem install bundler)
18 | * Appium 0.10.1 (http://appium.io/)
19 | * An Android Device (Nexus 4 Android Version 4.3)
20 |
21 | Steps:
22 | * Connect Android device then start the Appium server
23 |
24 | adb devices
25 | appium &
26 |
27 | * Build the App/APK (In another terminal)
28 |
29 | cd AndroidTestApp
30 | android update project --subprojects --target "android-18" --path .
31 | ant clean debug
32 | cd ..
33 |
34 | * Run the BDD tests
35 |
36 | bundle install
37 | bundle exec cucumber
38 |
39 |
40 |
--------------------------------------------------------------------------------
/AndroidTestApp/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/features/support/appium_custom.rb:
--------------------------------------------------------------------------------
1 | def button_exists? button
2 | $driver.find_elements(:xpath, "//button[contains(@value,\"#{button}\")]").count>0
3 | end
4 |
5 | def wait_for_button_to_exist button
6 | $wait.until {button_exists? button}
7 | end
8 |
9 | def click_button button
10 | wait_for_button_to_exist button
11 | $driver.find_element(:xpath, "//button[contains(@value,\"#{button}\")]").click
12 | end
13 |
14 | def xpath_exists? xpath
15 | $driver.find_elements(:xpath, xpath).count>0
16 | end
17 |
18 | def wait_for_xpath_to_exist xpath
19 | $wait.until { xpath_exists? xpath }
20 | end
21 |
22 | def click_xpath xpath
23 | wait_for_xpath_to_exist xpath
24 | $driver.find_element(:xpath, xpath).click
25 | end
26 |
27 | def id_exists? id
28 | $driver.find_elements(:id, id).count>0
29 | end
30 |
31 | def wait_for_id_to_exist id
32 | $wait.until { id_exists? id }
33 | end
34 |
35 | def click_id id
36 | wait_for_id_to_exist id
37 | $driver.find_element(:id, id).click
38 | end
39 |
40 | def id_text id
41 | wait_for_id_to_exist id
42 | $driver.find_element(:id, id).text
43 | end
44 |
45 | def text_exists? text
46 | $driver.find_elements(:xpath, "//text[contains(@value,\"#{text}\")]").count>0
47 | end
48 | def wait_for_text_to_exist text
49 | $wait.until {text_exists? text}
50 | end
51 |
52 | def click_text text
53 | wait_for_text_to_exist text
54 | $driver.find_element(:xpath, "//text[contains(@value,\"#{text}\")]").click
55 | end
56 |
57 | def fill_in id, text
58 | wait_for_id_to_exist id
59 | element = $driver.find_element(:id, id)
60 | element.clear
61 | element.send_keys text
62 | end
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/AndroidTestApp/src/com/example/androidtestapp/DisplayMessageActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.androidtestapp;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.annotation.TargetApi;
5 | import android.app.Activity;
6 | import android.content.Intent;
7 | import android.os.Build;
8 | import android.os.Bundle;
9 | import android.support.v4.app.NavUtils;
10 | import android.view.Menu;
11 | import android.view.MenuItem;
12 | import android.widget.TextView;
13 |
14 | public class DisplayMessageActivity extends Activity {
15 |
16 | @SuppressLint("NewApi")
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 |
21 |
22 | // Get the message from the intent
23 | Intent intent = getIntent();
24 | String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
25 |
26 | if (message.trim().equals("")) {
27 | message = "No message provided!";
28 | }
29 |
30 | // Create the text view
31 | TextView textView = new TextView(this);
32 | textView.setTextSize(40);
33 | textView.setText(message);
34 |
35 | // Set the text view as the activity layout
36 | setContentView(textView);
37 |
38 |
39 |
40 | setupActionBar();
41 | }
42 |
43 | /**
44 | * Set up the {@link android.app.ActionBar}, if the API is available.
45 | */
46 | @TargetApi(Build.VERSION_CODES.HONEYCOMB)
47 | private void setupActionBar() {
48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
49 | getActionBar().setDisplayHomeAsUpEnabled(true);
50 | }
51 | }
52 |
53 | @Override
54 | public boolean onCreateOptionsMenu(Menu menu) {
55 | // Inflate the menu; this adds items to the action bar if it is present.
56 | getMenuInflater().inflate(R.menu.display_message, menu);
57 | return true;
58 | }
59 |
60 | @Override
61 | public boolean onOptionsItemSelected(MenuItem item) {
62 | switch (item.getItemId()) {
63 | case android.R.id.home:
64 | // This ID represents the Home or Up button. In the case of this
65 | // activity, the Up button is shown. Use NavUtils to allow users
66 | // to navigate up one level in the application structure. For
67 | // more details, see the Navigation pattern on Android Design:
68 | //
69 | // http://developer.android.com/design/patterns/navigation.html#up-vs-back
70 | //
71 | NavUtils.navigateUpFromSameTask(this);
72 | return true;
73 | }
74 | return super.onOptionsItemSelected(item);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------