{"id":14969339,"url":"https://github.com/roroche/androidtestingbox","last_synced_at":"2025-10-26T07:31:23.774Z","repository":{"id":216979850,"uuid":"73503807","full_name":"RoRoche/AndroidTestingBox","owner":"RoRoche","description":"Android project to experiment various testing tools","archived":false,"fork":false,"pushed_at":"2020-04-26T16:49:41.000Z","size":752,"stargazers_count":63,"open_issues_count":2,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-01-31T16:53:38.100Z","etag":null,"topics":["android","assertj","cucumber","cucumber-jvm","espresso","fluent-assertions","frutilla","jgiven","junit","junit-hierarchicalcontextrunner","kluent","kotlin","robolectric","robotium","spectrum","spek","truth","zester"],"latest_commit_sha":null,"homepage":"https://roroche.github.io/AndroidTestingBox/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RoRoche.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-11T19:04:25.000Z","updated_at":"2023-09-08T17:17:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"7252e0cf-aa15-405a-8e87-65f34115ed79","html_url":"https://github.com/RoRoche/AndroidTestingBox","commit_stats":{"total_commits":52,"total_committers":2,"mean_commits":26.0,"dds":0.4807692307692307,"last_synced_commit":"814a9136a832ef90d5bbee0a350834b2ca9b4da1"},"previous_names":["roroche/androidtestingbox"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoRoche%2FAndroidTestingBox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoRoche%2FAndroidTestingBox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoRoche%2FAndroidTestingBox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RoRoche%2FAndroidTestingBox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RoRoche","download_url":"https://codeload.github.com/RoRoche/AndroidTestingBox/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238284883,"owners_count":19446747,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","assertj","cucumber","cucumber-jvm","espresso","fluent-assertions","frutilla","jgiven","junit","junit-hierarchicalcontextrunner","kluent","kotlin","robolectric","robotium","spectrum","spek","truth","zester"],"created_at":"2024-09-24T13:41:43.041Z","updated_at":"2025-10-26T07:31:23.442Z","avatar_url":"https://github.com/RoRoche.png","language":"Java","readme":"# AndroidTestingBox\r\n\r\nAndroid project to experiment various testing tools.\r\nIt targets **Java** and **Kotlin** languages.\r\nPriority is given to fluency and ease of use.\r\nThe idea is to provide a toolbox to write elegant and intelligible tests, with modern techniques like **behavior-driven testing frameworks** or **fluent assertions**.\r\n\r\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-AndroidTestingBox-brightgreen.svg?style=flat)](https://android-arsenal.com/details/3/4658)\r\n[![Android Weekly](https://img.shields.io/badge/Android%20Weekly-%23242-green.svg)](http://androidweekly.net/issues/issue-242)\r\n[![Dependency Status](https://www.versioneye.com/user/projects/58b85f8401b5b7003a2129e7/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/58b85f8401b5b7003a2129e7)\r\n\n![logo](https://raw.githubusercontent.com/RoRoche/AndroidTestingBox/master/assets/logo.png)\n\r\n\u003c!-- run the following command line: markdown-toc -i README.md --\u003e\n\n\u003c!-- toc --\u003e\n\n- [AndroidTestingBox in the news](#androidtestingbox-in-the-news)\n- [System under test (SUT)](#system-under-test-sut)\n  * [Simple Java class](#simple-java-class)\n  * [Android `Activity`](#android-activity)\n- [JUnit](#junit)\n  * [Fluent assertions: truth](#fluent-assertions-truth)\n    + [Alternative: AssertJ](#alternative-assertj)\n  * [Frutilla](#frutilla)\n  * [Fluent test method names](#fluent-test-method-names)\n  * [Specifications framework: Spectrum](#specifications-framework-spectrum)\n    + [Alternative: Oleaster](#alternative-oleaster)\n  * [Hierarchies in JUnit: junit-hierarchicalcontextrunner](#hierarchies-in-junit-junit-hierarchicalcontextrunner)\n    + [Novelty to consider: JUnit 5 Nested Tests](#novelty-to-consider-junit-5-nested-tests)\n  * [BDD tools](#bdd-tools)\n    + [Cucumber](#cucumber)\n    + [JGiven](#jgiven)\n  * [Mutation testing: Zester plugin](#mutation-testing-zester-plugin)\n  * [Alternative to JUnit: TestNG](#alternative-to-junit-testng)\n- [Kotlin](#kotlin)\n  * [Fluent assertions: Kluent](#fluent-assertions-kluent)\n    + [Alternative: Expekt](#alternative-expekt)\n  * [Specifications framework: Spek](#specifications-framework-spek)\n- [Android](#android)\n  * [Fluent assertions: AssertJ Android](#fluent-assertions-assertj-android)\n  * [Robotium](#robotium)\n  * [Espresso](#espresso)\n  * [Robolectric](#robolectric)\n  * [Cucumber support](#cucumber-support)\n  * [JGiven support](#jgiven-support)\n- [IDE configuration](#ide-configuration)\n- [Nota Bene](#nota-bene)\n- [Bibliography](#bibliography)\n- [Interesting repositories](#interesting-repositories)\n- [Interesting articles](#interesting-articles)\n- [Resources](#resources)\n- [Logo credits](#logo-credits)\n\n\u003c!-- tocstop --\u003e\n\n## AndroidTestingBox in the news\r\n\r\n* [Android Weekly #242](http://androidweekly.net/issues/issue-242)\r\n\r\n## System under test (SUT)\r\n\r\n### Simple Java class\r\n\r\n```java\r\npublic class Sum {\r\n    public final int a;\r\n    public final int b;\r\n    private final LazyInitializer\u003cInteger\u003e mSum;\r\n\r\n    public Sum(int a, int b) {\r\n        this.a = a;\r\n        this.b = b;\r\n        mSum = new LazyInitializer\u003cInteger\u003e() {\r\n            @Override\r\n            protected Integer initialize() throws ConcurrentException {\r\n                return Sum.this.a + Sum.this.b;\r\n            }\r\n        };\r\n    }\r\n\r\n    public int getSum() throws ConcurrentException {\r\n        return mSum.get();\r\n    }\r\n}\r\n```\r\n\r\n### Android `Activity`\r\n\r\nHere stands the layout file:\r\n\r\n```xml\r\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\r\n\u003cRelativeLayout\r\n    android:id=\"@+id/activity_main\"\r\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\u003e\r\n\r\n    \u003cTextView\r\n        android:id=\"@+id/ActivityMain_TextView\"\r\n        android:layout_width=\"wrap_content\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:layout_centerInParent=\"true\"\r\n        android:text=\"@string/app_name\"/\u003e\r\n\r\n    \u003cButton\r\n        android:id=\"@+id/ActivityMain_Button\"\r\n        android:layout_width=\"wrap_content\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:layout_below=\"@id/ActivityMain_TextView\"\r\n        android:layout_centerHorizontal=\"true\"\r\n        android:text=\"@string/click_me\"/\u003e\r\n\u003c/RelativeLayout\u003e\r\n\r\n```\r\n\r\nand here stands the corresponding `Activity`:\r\n\r\n```kotlin\r\nclass MainActivity : AppCompatActivity() {\r\n\r\n    override fun onCreate(savedInstanceState: Bundle?) {\r\n        super.onCreate(savedInstanceState)\r\n        setContentView(R.layout.activity_main)\r\n\r\n        val textView: TextView = findViewById(R.id.ActivityMain_TextView) as TextView\r\n        val button = findViewById(R.id.ActivityMain_Button)\r\n        button.setOnClickListener({ view: View -\u003e textView.setText(R.string.text_changed_after_button_click) })\r\n    }\r\n}\r\n```\r\n\r\n## JUnit\r\n\r\n### Fluent assertions: truth\r\n\r\n- \u003chttps://google.github.io/truth/\u003e\r\n\r\n#### Alternative: AssertJ\r\n\r\n* \u003chttp://joel-costigliola.github.io/assertj/\u003e\r\n\r\n### Frutilla\r\n\r\n- \u003chttps://github.com/ignaciotcrespo/frutilla\u003e\r\n\r\n```java\r\n@RunWith(value = org.frutilla.FrutillaTestRunner.class)\r\npublic class FrutillaSumTest {\r\n\r\n    @Frutilla(\r\n            Given = \"two numbers a = 1 and b = 3\",\r\n            When = \"computing the sum of these 2 numbers\",\r\n            Then = \"should compute sum = 4\"\r\n    )\r\n    @Test\r\n    public void test_addition_isCorrect() throws Exception {\r\n        given(\"two numbers\", () -\u003e {\r\n            final int a = 1;\r\n            final int b = 3;\r\n\r\n            when(\"computing the sum of these 2 numbers\", () -\u003e {\r\n                final Sum sum = new Sum(a, b);\r\n\r\n                then(\"should compute sum = 4\", () -\u003e assertThat(sum.getSum()).isEqualTo(4));\r\n            });\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n### Fluent test method names\r\n\r\n- \u003chttps://jijeshmohan.wordpress.com/2011/12/17/junit-readable-test-names/\u003e\r\n\r\n### Specifications framework: Spectrum\r\n\r\n- \u003chttps://github.com/greghaskins/spectrum\u003e\r\n- \u003chttp://www.greghaskins.com/archive/introducing-spectrum-bdd-style-test-runner-for-java-junit\u003e\r\n\r\n```java\r\nimport static com.google.common.truth.Truth.assertThat;\r\nimport static com.greghaskins.spectrum.Spectrum.describe;\r\nimport static com.greghaskins.spectrum.Spectrum.it;\r\n\r\n@RunWith(Spectrum.class)\r\npublic class SpectrumSumTest {\r\n    {\r\n        describe(\"Given two numbers a = 1 and b = 3\", () -\u003e {\r\n            final int a = 1;\r\n            final int b = 3;\r\n\r\n            it(\"computing the sum of these 2 numbers, should compute sum = 4\", () -\u003e {\r\n                final Sum sum = new Sum(a, b);\r\n\r\n                assertThat(sum.getSum()).isEqualTo(4);\r\n            });\r\n        });\r\n    }\r\n}\r\n```\r\n\r\n#### Alternative: Oleaster \r\n\r\n* \u003chttps://github.com/mscharhag/oleaster\u003e\r\n\r\n### Hierarchies in JUnit: junit-hierarchicalcontextrunner\r\n\r\n- \u003chttps://github.com/bechte/junit-hierarchicalcontextrunner\u003e\r\n\r\n```java\r\n@RunWith(HierarchicalContextRunner.class)\r\npublic class HCRSumTest {\r\n\r\n    public class GivenTwoNumbers1And3 {\r\n        private int a = 1;\r\n        private int b = 3;\r\n\r\n        @Before\r\n        public void setUp() {\r\n            a = 1;\r\n            b = 3;\r\n        }\r\n\r\n        public class WhenComputingSum {\r\n            private Sum sum;\r\n\r\n            @Before\r\n            public void setUp() {\r\n                sum = new Sum(a, b);\r\n            }\r\n\r\n            @Test\r\n            public void thenShouldBeEqualTo4() throws ConcurrentException {\r\n                assertThat(sum.getSum()).isEqualTo(4);\r\n            }\r\n        }\r\n\r\n        public class WhenMultiplying {\r\n            private int multiply;\r\n\r\n            @Before\r\n            public void setUp() {\r\n                multiply = a * b;\r\n            }\r\n\r\n            @Test\r\n            public void thenShouldBeEqualTo3() throws ConcurrentException {\r\n                assertThat(multiply).isEqualTo(3);\r\n            }\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n#### Novelty to consider: JUnit 5 Nested Tests\r\n\r\n- \u003chttp://junit.org/junit5/docs/current/user-guide/#writing-tests-nested\u003e\r\n- The `@Nested` and `@DisplayName` annotations allow developers to reach an elegant \"given/when/then\" canvas\r\n\r\n### BDD tools\r\n\r\n#### Cucumber\r\n\r\n- \u003chttps://cucumber.io/\u003e\r\n\r\n* Define the `.feature` file:\r\n\r\n```gherkin\r\nFeature: Sum computation\r\n\r\n  Scenario Outline: Sum 2 integers\r\n    Given two int \u003ca\u003e and \u003cb\u003e to sum\r\n    When computing sum\r\n    Then it should be \u003csum\u003e\r\n\r\n    Examples:\r\n      |  a |  b | sum |\r\n      |  1 |  3 |   4 |\r\n      | -1 | -3 |  -4 |\r\n      | -1 |  3 |   2 |\r\n```\r\n\r\n* Define the corresponding steps:\r\n\r\n```java\r\npublic class SumSteps {\r\n    Sum moSum;\r\n    int miSum;\r\n\r\n    @Given(\"^two int (-?\\\\d+) and (-?\\\\d+) to sum$\")\r\n    public void twoIntToSum(final int a, final int b) {\r\n        moSum = new Sum(a, b);\r\n    }\r\n\r\n    @When(\"^computing sum$\")\r\n    public void computingSum() throws ConcurrentException {\r\n        miSum = moSum.getSum();\r\n    }\r\n\r\n    @Then(\"^it should be (-?\\\\d+)$\")\r\n    public void itShouldBe(final int expected) {\r\n        Assert.assertEquals(expected, miSum);\r\n    }\r\n}\r\n```\r\n\r\n* Define the specific runner:\r\n\r\n```java\r\n@RunWith(Cucumber.class)\r\n@CucumberOptions(\r\n        features = \"src/test/resources/\"\r\n)\r\npublic class SumTestRunner {\r\n}\r\n```\r\n\r\n* Relevant tools:\r\n    * to write Gherkin features: [Tidy Gherkin](https://chrome.google.com/webstore/detail/tidy-gherkin/nobemmencanophcnicjhfhnjiimegjeo?hl=en-GB)\r\n    * to display Gherkin features in Chrome a way pretty way: [Pretty Gherkin](https://chrome.google.com/webstore/detail/pretty-gherkin/blemhogdenfkkojlpghcinocbfjheioc?hl=en-GB)\r\n    * to generating specifications from Gherkin source files: [featurebook](https://www.npmjs.com/package/featurebook)\r\n\r\n#### JGiven\r\n\r\n- \u003chttp://jgiven.org/\u003e\r\n\r\n```java\r\npublic class JGivenSumTest extends SimpleScenarioTest\u003cJGivenSumTest.TestSteps\u003e {\r\n\r\n    @Test\r\n    public void addition_isCorrect() throws ConcurrentException {\r\n        given().first_number_$(1).and().second_number_$(3);\r\n        when().computing_sum();\r\n        then().it_should_be_$(4);\r\n    }\r\n\r\n    public static class TestSteps extends Stage\u003cTestSteps\u003e {\r\n        private int mA;\r\n        private int mB;\r\n        private Sum mSum;\r\n\r\n        public TestSteps first_number_$(final int piA) {\r\n            mA = piA;\r\n            return this;\r\n        }\r\n\r\n        public void second_number_$(final int piB) {\r\n            mB = piB;\r\n        }\r\n\r\n        public void computing_sum() {\r\n            mSum = new Sum(mA, mB);\r\n        }\r\n\r\n        public void it_should_be_$(final int piExpected) throws ConcurrentException {\r\n            assertThat(mSum.getSum()).isEqualTo(piExpected);\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n### Mutation testing: Zester plugin\r\n\r\n- \u003chttps://plugins.jetbrains.com/plugin/8281\u003e\r\n- \u003chttps://tech.zalando.com/blog/zester-mutation-testing/\u003e\r\n\r\nFor this sample project, define a new \"Run configuration\" with Zester such as:\r\n\r\n```\r\nTarget classes: com.guddy.android_testing_box.zester.*\r\nTest class: com.guddy.android_testing_box.zester.ZesterExampleTest\r\n```\r\n\r\nIt generates an HTML report in the `build/reports/zester/` directory, showing that 2 \"mutants\" survived to unit tests (so potential bugs, and in this case, yes it is).\r\n\r\n### Alternative to JUnit: TestNG\r\n\r\n* \u003chttp://testng.org/doc/index.html\u003e\r\n\r\n## Kotlin \r\n\r\n### Fluent assertions: Kluent\r\n\r\n- \u003chttps://github.com/MarkusAmshove/Kluent\u003e\r\n\r\n#### Alternative: Expekt\r\n\r\n* \u003chttps://github.com/winterbe/expekt\u003e\r\n\r\n### Specifications framework: Spek\r\n\r\n- \u003chttps://github.com/JetBrains/spek\u003e\r\n- \u003chttp://jetbrains.github.io/spek/docs/latest/#setting-up\u003e\r\n\r\n```kotlin\r\n@RunWith(JUnitPlatform::class)\r\nclass SpekSumTest : Spek({\r\n\r\n    given(\"two numbers a = 1 and b = 3\") {\r\n        val a: Int = 1\r\n        val b: Int = 3\r\n\r\n        on(\"computing the sum of these 2 numbers\") {\r\n            val sum: Sum = Sum(a, b)\r\n\r\n            it(\"should compute sum = 4\") {\r\n                sum.sum shouldBe 4\r\n            }\r\n        }\r\n    }\r\n})\r\n```\r\n\r\n## Android\r\n\r\n### Fluent assertions: AssertJ Android\r\n\r\n- \u003chttp://square.github.io/assertj-android/\u003e\r\n\r\n### Robotium\r\n\r\n- \u003chttps://github.com/RobotiumTech/robotium\u003e\r\n\r\n```java\r\n@RunWith(AndroidJUnit4.class)\r\npublic class MainActivityTest {\r\n    //region Rule\r\n    @Rule\r\n    public final ActivityTestRule\u003cMainActivity\u003e mActivityTestRule = new ActivityTestRule\u003c\u003e(MainActivity.class, true, false);\r\n    //endregion\r\n\r\n    //region Fields\r\n    private Solo mSolo;\r\n    private MainActivity mActivity;\r\n    private Context mContextTarget;\r\n    //endregion\r\n\r\n    //region Test lifecycle\r\n    @Before\r\n    public void setUp() throws Exception {\r\n        mActivity = mActivityTestRule.getActivity();\r\n        mSolo = new Solo(InstrumentationRegistry.getInstrumentation(), mActivity);\r\n        mContextTarget = InstrumentationRegistry.getTargetContext();\r\n    }\r\n\r\n    @After\r\n    public void tearDown() throws Exception {\r\n        mSolo.finishOpenedActivities();\r\n    }\r\n    //endregion\r\n\r\n    //region Test methods\r\n    @Test\r\n    public void testTextDisplayed() throws Exception {\r\n        given(\"the main activity\", () -\u003e {\r\n\r\n            when(\"launching activity\", () -\u003e {\r\n                mActivity = mActivityTestRule.launchActivity(null);\r\n\r\n                then(\"should display 'app_name'\", () -\u003e {\r\n                    final boolean lbFoundAppName = mSolo.waitForText(mContextTarget.getString(R.string.app_name), 1, 5000L, true);\r\n                    assertThat(lbFoundAppName);\r\n                });\r\n            });\r\n        });\r\n    }\r\n    //endregion\r\n}\r\n```\r\n\r\n### Espresso\r\n\r\n- \u003chttps://google.github.io/android-testing-support-library/docs/espresso/\u003e\r\n\r\n### Robolectric\r\n\r\n- \u003chttp://robolectric.org/\u003e\r\n- \u003chttp://robolectric.org/using-add-on-modules/\u003e \r\n\r\n```groovy\r\n    testCompile 'org.robolectric:robolectric:3.2.2'\r\n    testCompile 'org.robolectric:shadows-multidex:3.2.2'\r\n    testCompile 'org.robolectric:shadows-support-v4:3.2.2'\r\n    testCompile 'org.khronos:opengl-api:gl1.1-android-2.1_r1'\r\n```\r\n\r\n```java\r\n@RunWith(RobolectricTestRunner.class)\r\n@Config(constants = BuildConfig.class)\r\npublic class RobolectricMainActivityTest {\r\n\r\n    @Test\r\n    public void test_clickingButton_shouldChangeText() throws Exception {\r\n\r\n        given(\"The MainActivity\", () -\u003e {\r\n            final MainActivity loActivity = Robolectric.setupActivity(MainActivity.class);\r\n            final Button loButton = (Button) loActivity.findViewById(R.id.ActivityMain_Button);\r\n            final TextView loTextView = (TextView) loActivity.findViewById(R.id.ActivityMain_TextView);\r\n\r\n            when(\"clicking on the button\", () -\u003e {\r\n                loButton.performClick();\r\n\r\n                then(\"text should have changed\", () -\u003e assertThat(loTextView.getText().toString()).isEqualTo(\"Text changed after button click\"));\r\n            });\r\n        });\r\n    }\r\n\r\n}\r\n```\r\n\r\n### Cucumber support\r\n\r\n- \u003chttps://github.com/cucumber/cucumber-jvm/tree/master/examples/android\u003e\r\n\r\n* Configure the `build.gradle` file:\r\n\r\n```groovy\r\nandroid {\r\n    defaultConfig {\r\n        testApplicationId \"com.guddy.android_testing_box.ui\"\r\n        testInstrumentationRunner \"com.guddy.android_testing_box.ui.CucumberInstrumentationRunner\"\r\n    }\r\n    \r\n    sourceSets {\r\n        androidTest {\r\n            assets.srcDirs = ['src/androidTest/assets']\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n* Write features in the `src/androidTest/assets` directory, for example this `main.feature` file:\r\n\r\n```gherkin\r\nFeature: Main activity\r\n\r\n  Scenario: Click on the button\r\n    Given the initial state is shown\r\n    When clicking on the button\r\n    Then the text changed to \"Text changed after button click\"\r\n```\r\n\r\n* Define the corresponding steps:\r\n\r\n```java\r\n@CucumberOptions(features = \"features\")\r\npublic class CucumberMainActivitySteps extends ActivityInstrumentationTestCase2\u003cMainActivity\u003e {\r\n\r\n    public CucumberMainActivitySteps() {\r\n        super(MainActivity.class);\r\n    }\r\n\r\n    @Given(\"^the initial state is shown$\")\r\n    public void the_initial_main_activity_is_shown() {\r\n        // Call the activity before each test.\r\n        getActivity();\r\n    }\r\n\r\n    @When(\"^clicking on the button$\")\r\n    public void clicking_the_Click_Me_button() {\r\n        onView(withId(R.id.ActivityMain_Button)).perform(click());\r\n    }\r\n\r\n    @Then(\"^the text changed to \\\"([^\\\"]*)\\\"$\")\r\n    public void text_$_is_shown(final String s) {\r\n        onView(withId(R.id.ActivityMain_TextView)).check(matches(withText(s)));\r\n    }\r\n}\r\n```\r\n\r\n* Define the specific runner:\r\n\r\n```java\r\npublic class CucumberInstrumentationRunner extends MonitoringInstrumentation {\r\n\r\n    private final CucumberInstrumentationCore mInstrumentationCore = new CucumberInstrumentationCore(this);\r\n\r\n    @Override\r\n    public void onCreate(Bundle arguments) {\r\n        super.onCreate(arguments);\r\n\r\n        mInstrumentationCore.create(arguments);\r\n        start();\r\n    }\r\n\r\n    @Override\r\n    public void onStart() {\r\n        super.onStart();\r\n\r\n        waitForIdleSync();\r\n        mInstrumentationCore.start();\r\n    }\r\n}\r\n```\r\n\r\n### JGiven support\r\n\r\n- \u003chttp://jgiven.org/userguide/#_android\u003e\r\n- \u003chttps://github.com/TNG/JGiven/tree/master/example-projects/android\u003e\r\n\r\n```java\r\n@RunWith(AndroidJUnit4.class)\r\npublic class EspressoJGivenMainActivityTest extends\r\n        SimpleScenarioTest\u003cEspressoJGivenMainActivityTest.Steps\u003e {\r\n\r\n    @Rule\r\n    @ScenarioState\r\n    public ActivityTestRule\u003cMainActivity\u003e activityTestRule = new ActivityTestRule\u003c\u003e(MainActivity.class);\r\n\r\n    @Rule\r\n    public AndroidJGivenTestRule androidJGivenTestRule = new AndroidJGivenTestRule(this.getScenario());\r\n\r\n    @Test\r\n    public void clicking_ClickMe_changes_the_text() {\r\n        given().the_initial_main_activity_is_shown()\r\n                .with().text(\"AndroidTestingBox\");\r\n        when().clicking_the_Click_Me_button();\r\n        then().text_$_is_shown(\"Text changed after button click\");\r\n    }\r\n\r\n    public static class Steps extends Stage\u003cSteps\u003e {\r\n        @ScenarioState\r\n        CurrentStep currentStep;\r\n\r\n        @ScenarioState\r\n        ActivityTestRule\u003cMainActivity\u003e activityTestRule;\r\n\r\n        public Steps the_initial_main_activity_is_shown() {\r\n            // nothing to do, just for reporting\r\n            return this;\r\n        }\r\n\r\n        public Steps clicking_the_Click_Me_button() {\r\n            onView(withId(R.id.ActivityMain_Button)).perform(click());\r\n            return this;\r\n        }\r\n\r\n        public Steps text(@Quoted String s) {\r\n            return text_$_is_shown(s);\r\n        }\r\n\r\n        public Steps text_$_is_shown(@Quoted String s) {\r\n            onView(withId(R.id.ActivityMain_TextView)).check(matches(withText(s)));\r\n            takeScreenshot();\r\n            return this;\r\n        }\r\n\r\n        private void takeScreenshot() {\r\n            currentStep.addAttachment(\r\n                    Attachment.fromBinaryBytes(ScreenshotUtils.takeScreenshot(activityTestRule.getActivity()), MediaType.PNG)\r\n                            .showDirectly());\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## IDE configuration\r\n\r\n- MoreUnit plugin:  \u003chttps://plugins.jetbrains.com/plugin/7105\u003e\r\n\r\n## Nota Bene\r\n\r\nA relevant combination of [Dagger2](https://google.github.io/dagger/) and [mockito](http://site.mockito.org/) is already described in a previous post I wrote: \u003chttp://roroche.github.io/AndroidStarter/\u003e\r\n\r\n## Bibliography\r\n\r\n- \u003chttps://blog.codecentric.de/en/2016/01/writing-better-tests-junit/\u003e\r\n- \u003chttps://www.petrikainulainen.net/programming/unit-testing/3-reasons-why-we-should-not-use-inheritance-in-our-tests/\u003e\r\n- \u003chttp://blog.xebia.com/mutation-testing-how-good-are-your-unit-tests/\u003e\r\n\r\n## Interesting repositories\r\n\r\n- \u003chttps://github.com/googlesamples/android-testing\u003e\r\n- \u003chttps://github.com/TNG/JGiven/tree/master/jgiven-examples\u003e\r\n- \u003chttps://github.com/ahus1/bdd-examples\u003e\r\n- \u003chttps://github.com/chiuki/android-test-demo\u003e\r\n\r\n## Interesting articles\r\n\r\n- \u003chttps://www.philosophicalhacker.com/post/some-resources-for-learning-how-to-test-android-apps/\u003e\r\n- \u003chttps://www.sitepoint.com/property-based-testing-with-javaslang/\u003e\r\n- \u003chttps://medium.com/@fabioCollini/android-testing-using-dagger-2-mockito-and-a-custom-junit-rule-c8487ed01b56\u003e\r\n- \u003chttps://offbeattesting.com/2017/04/13/unit-test/\u003e\r\n\r\n## Resources\r\n\r\n- \u003chttps://www.petrikainulainen.net/writing-clean-tests/\u003e\r\n- \u003chttps://www.petrikainulainen.net/category/weekly/\u003e\r\n\n## Logo credits\n\nScience graphic by \u003ca href=\"http://www.flaticon.com/authors/pixel-perfect\"\u003ePixel perfect\u003c/a\u003e from \u003ca href=\"http://www.flaticon.com/\"\u003eFlaticon\u003c/a\u003e is licensed under \u003ca href=\"http://creativecommons.org/licenses/by/3.0/\" title=\"Creative Commons BY 3.0\"\u003eCC BY 3.0\u003c/a\u003e. Made with \u003ca href=\"http://logomakr.com\" title=\"Logo Maker\"\u003eLogo Maker\u003c/a\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froroche%2Fandroidtestingbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froroche%2Fandroidtestingbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froroche%2Fandroidtestingbox/lists"}