{"id":699,"date":"2020-01-29T20:20:41","date_gmt":"2020-01-29T19:20:41","guid":{"rendered":"http:\/\/blog.ansuz.nl\/?p=699"},"modified":"2020-01-29T20:20:42","modified_gmt":"2020-01-29T19:20:42","slug":"cucumber-android","status":"publish","type":"post","link":"http:\/\/blog.ansuz.nl\/index.php\/2020\/01\/29\/cucumber-android\/","title":{"rendered":"Cucumber &#038; Android"},"content":{"rendered":"\n<p>A while ago, the agile\/scrum team I was part of was looking for a way to record functional requirements for the app we were working on. After looking around for a bit, we came across <a href=\"https:\/\/en.wikipedia.org\/wiki\/Behavior-driven_development\">Behaviour-Driven Development<\/a> (BDD) and <a href=\"https:\/\/cucumber.io\/\">Cucumber<\/a>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p> Although documentation and automated tests are produced by a BDD team, you can think of them as nice side-effects. The real goal is valuable, working software, and the fastest way to get there is through conversations between the people who are involved in imagining and delivering that software. <\/p><cite><a href=\"https:\/\/cucumber.io\/docs\/bdd\/\">Cucumber.io on BDD<\/a><br><br><\/cite><\/blockquote>\n\n\n\n<p>Since we wanted to test the Android and iOS using the same Gherkin scenarios, we set up Cucumber together with <a href=\"http:\/\/appium.io\/\">Appium<\/a>. Personally I find working with Appium too cumbersome. In a private project I&#8217;ve therefore set up Cucumber with Android and left Appium out of the equation.<\/p>\n\n\n\n<p>In this article I&#8217;ll explain how to set up Cucumber for Android.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Set up cucumber-android<\/h2>\n\n\n\n<p>Add the &#8220;<a href=\"https:\/\/github.com\/cucumber\/cucumber-android\">cucumber-android<\/a>&#8221; library to your project:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>androidTestImplementation \"io.cucumber:cucumber-android:$cucumberVersion\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Custom TestRunner<\/h2>\n\n\n\n<p>To configure Cucumber we&#8217;ll create a custom &#8220;<em>TestRunner<\/em>&#8216;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private const val PLUGIN_KEY = \"plugin\"\nprivate const val REPORTS_DIR = \"reports\/cucumber\"\n\nprivate const val REPORTER_PLUGIN_PATTERN =\n    \"junit:%s\/cucumber-junit.xml--\" +\n    \"html:%s\/cucumber-html--\" +\n    \"json:%s\/cucumber.json\"\n\n\/**\n * The CucumberOptions annotation is mandatory for exactly one of the classes in the test project.\n * Creating a custom test Runner seems the simplest way to achieve that.\n *\/\n@CucumberOptions(\n    features = [\"cucumber\/features\"],\n    glue = [\"nl.ansuz.android.test\"]\n)\nclass CucumberRunner : CucumberAndroidJUnitRunner() {\n\n    override fun onCreate(bundle: Bundle?) {\n        bundle?.putString(PLUGIN_KEY, getPluginConfiguration())\n        super.onCreate(bundle)\n    }\n\n    private fun getPluginConfiguration(): String {\n        val path = getReportsPath()\n        return REPORTER_PLUGIN_PATTERN.format(path, path, path)\n    }\n\n    private fun getReportsPath(): String =\n        File(targetContext.getExternalFilesDir(null), REPORTS_DIR).absolutePath\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Permissions<\/h2>\n\n\n\n<p>To make reporting work, we need to give our app permission to write to the external storage. Since Cucumber will run under the &#8220;<em>androidTest<\/em>&#8221;  flavor, you can add the extra permissions in &#8220;<em>src\/androidTest\/AndroidManifest.xml<\/em>&#8221; to avoid polluting your production app with unnecessary permissions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" \/><\/code><\/pre>\n\n\n\n<p>Now Cucumber can save test reports on the external storage.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Writing Gherkin<\/h2>\n\n\n\n<p>The next step is to write some scenarios so there is something for Cucumber to test.  <br>The <a href=\"http:\/\/cucumber.io\/\">cucumber.io<\/a> website comes with plenty of examples, so I&#8217;ll leave this as an exercise for the reader.<\/p>\n\n\n\n<p><strong><em>Note:<\/em><\/strong> The &#8220;cucumber-android&#8221; plugin expects all feature files to be created under &#8220;<em>app\/src\/androidTest\/assets<\/em>&#8220;. You can tweak the base path by changing the &#8220;features&#8221; property of the &#8220;<em>CucumberOptions<\/em>&#8221; annotation in the custom &#8220;<em>TestRunner<\/em>&#8221; we created earlier.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Running tests<\/h2>\n\n\n\n<p>Now that everything is set up and we have a first test, we can run it. Because of the custom test runner, I had to create a Gradle task that will run instrumentation tests with it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>task runCucumberInstrumentationTests(type: Exec) {\n     description 'Runs instrumentation tests with Cucumber'\n     group 'verification'\n     dependsOn 'installDebug', 'installDebugAndroidTest'\n     commandLine 'adb', 'shell', 'am', 'instrument', '-w', 'nl.ansuz.android.test\/nl.ansuz.android.test.CucumberRunner'\n }<\/code><\/pre>\n\n\n\n<p>When you run this new task, no tests pass, but the Cucumber reports are generated anyway. To make the tests pass,we have to create some &#8220;glue&#8221;.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Writing the glue<\/h2>\n\n\n\n<p>In the custom &#8220;<em>TestRunner<\/em>&#8221; we&#8217;ve also defined where the &#8220;<em>cucumber-android<\/em>&#8221; library can find the &#8220;glue&#8221; to match scenarios with step definitions.<\/p>\n\n\n\n<p>The easiest way to write your step definitions is to annotate the appropriate methods in your <a href=\"https:\/\/developer.android.com\/training\/testing\/espresso\">Espresso<\/a> tests with Cucumber annotations, e.g.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@When(\"the Maker starts a game\")\nfun startGame() {\n  ...\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Pulling Cucumber reports<\/h2>\n\n\n\n<p>Now that you have written some tests, can run them and they pass, you want to be able to have a look at the Cucumber report(s) as well. Pulling the reports is fairly simple, all we need to do is add a Gradle task that uses &#8220;<em>adb pull<\/em>&#8221; to do this for us.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>task pullCucumberReports(type: Exec) {\n    description 'Pulls the Cucumber reports from the emulator.'\n    group 'verification'\n    dependsOn 'runCucumberInstrumentationTests'\n\n    workingDir buildDir\n    commandLine 'mkdir', '-p', 'reports'\n    commandLine 'adb', 'pull', '\/mnt\/sdcard\/Android\/data\/nl.ansuz.android\/files\/reports\/cucumber', 'reports'\n}<\/code><\/pre>\n\n\n\n<p>The reports path is set in the &#8220;<em>REPORTS_DIR<\/em>&#8221; constant in the custom &#8220;<em>TestRunner<\/em>&#8221; from earlier. Make sure that the paths in the test runner and the Gradle task match.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cleaning up<\/h2>\n\n\n\n<p>So far we are able to run Cucumber tests and pull the reports from the device. What is missing is a way to clean up after testing has finished. Again we&#8217;ll add a new Gradle task to do this for us.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>task uninstallCucumberTest() {\n    description 'Uninstalls the debug and debugAndroidTest apps.'\n    group 'install'\n    dependsOn 'uninstallDebug', 'uninstallDebugAndroidTest'\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Tying it all together<\/h2>\n\n\n\n<p>Because we are good developers and we are lazy, we don&#8217;t want to execute three different Gradle tasks to run tests, pull reports and clean up. Let&#8217;s introduce one last Gradle task to make our lives even easier.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>task cucumberCheck() {\n    description 'Installs regular and instrumentation apps, runs Cucumber tests, pulls reports ' +\n            'and then uninstall both apps.'\n    group 'verification'\n    dependsOn 'pullCucumberReports'\n}\n\ncucumberCheck.finalizedBy uninstallCucumberTest<\/code><\/pre>\n\n\n\n<p>I hope this helps you to get you started on using BDD for your Android project with Cucumber.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Bonus: IntelliJ \/ Android Studio plugins<\/h2>\n\n\n\n<p>To make working with Cucumber and Gherkin easier, you can install the following plugins for IntelliJ or Android Studio:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>&#8220;Gherkin&#8221; which provides support for the Gherkin language.<\/li><li>&#8220;Cucumber for Kotlin&#8221; which enables Cucumber support with step definitions in Kotlin.<\/li><li>&#8220;Cucumber for Java&#8221; which enables Cucumber support with step definitions in Java.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Further reading<\/h2>\n\n\n\n<p>If you want to learn more about Cucumber, I can highly recommend reading &#8220;<a href=\"https:\/\/pragprog.com\/book\/hwcuc2\/the-cucumber-book-second-edition\">The Cucumber Book<\/a>&#8221; by Matt Wynne and Aslak Helles\u00f8y, with Steve Tooke. <\/p>\n\n\n\n<p>For an introduction into BDD and Gherkin, the <a href=\"https:\/\/cucumber.io\/\">cucumber.io<\/a> website offers a lot of documentation:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/cucumber.io\/docs\/bdd\/\">BDD<\/a><\/li><li><a href=\"https:\/\/cucumber.io\/docs\/cucumber\/\">Cucumber<\/a><\/li><li><a href=\"https:\/\/cucumber.io\/docs\/gherkin\/\">Gherkin<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Notes<\/h2>\n\n\n\n<p>Software versions used at the time of writing:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Gradle: 5.2.1<\/li><li>cucumber-android version: 4.2.5<\/li><\/ul>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>A while ago, the agile\/scrum team I was part of was looking for a way to record functional requirements for the app we were working on. After looking around for a bit, we came across Behaviour-Driven Development (BDD) and Cucumber. &hellip; <a href=\"http:\/\/blog.ansuz.nl\/index.php\/2020\/01\/29\/cucumber-android\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[112,160],"tags":[125,162,163,164,161],"class_list":["post-699","post","type-post","status-publish","format-standard","hentry","category-android","category-testing","tag-android-2","tag-bdd","tag-cucumber","tag-gherkin","tag-testing"],"_links":{"self":[{"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/posts\/699","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/comments?post=699"}],"version-history":[{"count":32,"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/posts\/699\/revisions"}],"predecessor-version":[{"id":731,"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/posts\/699\/revisions\/731"}],"wp:attachment":[{"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/media?parent=699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/categories?post=699"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.ansuz.nl\/index.php\/wp-json\/wp\/v2\/tags?post=699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}