Engineering

15 Nov 2021

Introduction to Gherkin Tests automation for Android with Espresso

In this article we’ll explore writing automated user interface (UI) tests for Android using a testing framework called Espresso. We’ll then take a look at improving the tests by introducing a Gherkin style through the use of the Green Coffee library.

Why write automated tests when we can just manually test the app?

When a new feature is integrated into an app, tests must be run to ensure that the previous features are still working as expected and that no defects have been introduced. Manually testing the app may be an easy task at first, but as the app grows and new features are added, this will be a time and resource intensive task that can be costly. It is also prone to user error. 
The solution to this problem is writing automation tests. Once the tests have been created, they can be run repeatedly at no additional cost, plus they run faster than manual tests.

Writing UI Tests with Espresso

We have built a simple Android app that displays a list of people. The first screen shows the names, surnames, ages, weights and statuses of people. When a user taps on a name, the app navigates to the details screen. The details screen must display the correct information of the person that was tapped. We will write UI tests to make sure that the list of names is displayed, and that the details screen shows the correct information.

Writing UI Tests for the People App

First, we need to make sure that the Espresso testing dependencies are present in the app's build.gradle file. Expresso has a dependency on JUnit, therefore we need to ensure it is present in the gradle file.
Here are the required dependencies, if you don’t have them copy and paste them to your project and hit the “Sync Now” button.

testImplementation 'junit:junit:4.+'
AndroidTestImplementation 'Androidx.test.ext:junit:1.1.1'
AndroidTestImplementation 'Androidx.test.espresso:espresso-core:3.2.0'

At this point we have the required testing dependencies, let’s write our UI Tests! In Android Studio, the UI Tests can be located at app > java > package.name(AndroidTest)

Create a Kotlin class and name it such that it is clear what kind of tests it contains. The list of people is in the MainActivity, therefore we’ll name this class “MainActivityEspressoTest”. We need to indicate to Android Studio that this class is for testing by annotating it with @RunWith

@RunWith(AndroidJUnit4.class)
class MainActivityEspressoTest {
    
}

At this point Android Studio knows that the class is for testing and it will use JUnit because Expresso depends on it. We then need to launch the MainActivity for this class. It is done using the snippet below.

@RunWith(AndroidJUnit4.class)
class MainActivityEspressoTest {
    @Rule
    var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule<T>

Adding a @Rule annotation to code will set a precondition for the test.
The line of code following the @Rule declarator will execute before running the tests. We’ll now add our first test to check if at least one person is displayed. The name and surname of the person is John Smith.

@RunWith(AndroidJUnit4.class)
class MainActivityEspressoTest {
    @Rule
    var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule<T>(MainActivity::class.java)

    @Test
    fun iSeeHihHerNameIs {

        onView(componentHostWithText(containsString("John Smith"))).check(matches(isDisplayed()))
    }

The @Test declarator indicates that the function is a test. We won’t go into details on each of the Espresso functions, but checkIsPersonDisplayed( ) will check if “John Smith” is visible on the screen. At this point we need to write a test that will tap on John Smith, and then check if the next screen displays the correct name.

@RunWith(AndroidJUnit4.class)
class MainActivityEspressoTest {
    @Rule
    var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule<T>(MainActivity::class.java)

    @Test
    fun iSeeTheDetailScreenFor() {

	    onViewWithText(“John Smith”).isDisplayed
    }

    @Test
    fun iSeeHisHerNameIs() {
                 onViewWithText(“John Smith”).perform(click())

Writing UI Tests like this for huge projects may cause confusion as there is no simple way of telling what the test is testing, or how to get to the location where the test will run. A solution to this problem is to introduce Gherkin, and to use the Green Coffee library to run Gherkin tests.

Gherkin

Gherkin is a domain specific language used to write acceptance criteria. Gherkin has five statements:

  1. Scenario – It’s the label for the behavior you’re going to describe. Each file may have multiple scenarios. The keyword Scenario is a synonym of the keyword Example.

  2. Given – They are used to describe the initial context of the system - the scene of the scenario. It is typically something that happened in the past.

  3.  When – Describes an event. This can be a person interacting with the system, or it can be an event triggered by another system.

  4. Then – Describe an expected outcome.  The step definition of a Then step should use an assertion to compare the actual outcome (what the system actually does) to the expected outcome (what the step says the system is supposed to do).

  5. And – Used to replace successive Given’s, When’s and Then’s

Below are Gherkin statements that we will use to write our UI Tests:

Scenario: User launches the app.
Given: the user has opened the app.
When: the app has launched.
Then: a user should see a list of people with “John Smith” in the list.

Scenario: User navigates to the details screen.
Given: the app has launched.
And: a list of people is displayed
When: the user taps on “John Smith”.
Then: the app should navigate to the details screen.
And: the text “John Smith” should be visible.

Green Coffee

Green Coffee is a library that allows you to run your acceptance tests written in Gherkin in your Android instrumentation tests using the step definitions that you declare. We need to set up our project to use Green Coffee. In the app's build.gradle file, add the below dependency and then sync.

AndroidTestImplementation 'com.github.mauriciotogneri:green-coffee:3.6.0'

We create an assets folder and add our feature file in this folder. A feature file is a file that contains Gherkin statements. We’ll name our file “scenarios.feature”, the extension must be .feature

Feature: People and Details

Scenario: User launches the app.
Given the user has opened the app.
When the app has launched.
Then a user should see a list of people with “John Smith” in the list.

Scenario: The app has launched.
Given the user has launched the app.
And a list of people is displayed.
When the user taps on “John Smith”.
Then the app should navigate to the details screen.
And the text “John Smith” should be visible

Let’s modify our test class to use GreenCoffee():

@RunWith(Parameterized::class)
class MainActivityEspressoTest(scenarioConfig: ScenarioConfig?) : GreenCoffeeTest(scenarioConfig) {
    	@Rule
 	   var activity: ActivityTestRule<MainActivity> = ActivityTestRule<T>

Now the test class is inheriting from the GreenCoffeeTest class and it’s passing an instance of the scenario configuration to the constructor. The @Rule will launch MainActivity before any test is run.

Now the tests will not live in this file, they will live in another file called “steps”.

Steps are bits of code that check if the Gherkin statements pass or not, we need to indicate to our test file to run the steps and where to find the feature file that contains the scenarios. Below the @Rule code, we have the following block of code where we pass our feature files from the GreenCoffeeConfig(). This enables us to reference the feature files. 

companion object {
 @Parameters(name = "{0}")
 @Throws(IOException::class)
    fun scenarios(): Iterable<ScenarioConfig> {
        	return GreenCoffeeConfig()
                	.withFeatureFromAssets("assets/scenarios.feature")
                	    .takeScreenshotOnFail()
                	.scenarios(
                        	Locale("en", "GB")
	)
    }
}

The above block of code tells the test file where the feature file is, at this point we need to tell the file to run the steps. The code below does that, paste it under the companion object:

@Test
fun test() {
  	  start(new PeopleAndDetailsSteps())
}

We create a new Kotlin class and call it PeopleAndDetailsSteps, this is where we’ll write tests for the scenarios feature file.

class PeopleAndDetailsSteps : GreenCoffeeSteps() {
    
}

In this class we add our steps, starting with the check if “John Smith” is present in the list of people. We will also select it. In order to reference the statement that the step is testing we add the following code.

@Then("I select the contact \'(.+)\'$")
fun iSelectTheContactCalled(name: String) {
   	 onViewWithText(name).perfom(click)
}

The Green Coffee framework will find the scenario for this step and will inject “John Smith” as the name argument in the test function/step. 

This is extremely powerful because later if we want to test for a different name, we’ll only have to edit the feature file only.

At this point anyone reading this bit of code will know what the step is testing because of the statement above the step. This is the advantage of using Espresso with Green Coffee to write UI Tests.

We now add a step for checking if the details screen shows the correct name:

@And("I see the detail screen for \'(.+)\’")
fun iSeeTheDetailScreenFor$ (name: String) {
    	onViewWithText(name).isDisplayed
}

This step will run the last statement in our feature file. We will not cover the navigation steps and checking for other statements as this is just an introductory article on UI Testing. This is how your step file should look like after adding the above steps:

class PeopleAndDetailSteps: GreenCoffeeSteps() {
  @Then("I select the contact \'(.+)\'$")
  fun iSelectTheContactCalled(name: String) {
      onViewWithText(name).perfom(click)
  }
  @And("I see the detail screen for \'(.+)\’")
  fun iSeeTheDetailScreenFor$ (name: String) {
        onViewWithText(name).isDisplayed
  }
}

Conclusion

UI Testing is an important part of software development and writing UI Tests in Gherkin makes it easy for anyone to understand what exactly the function is testing and what are the steps required to get to the screen being tested. Using Gherkin syntax also introduces a flexibility as you can inject values as you change the test parameters.

Download the sample project

Learn more

Explore our services

Our services are design to bring your idea to life.
Explore our digital services to learn more.
Our services are design to bring your idea to life. Explore our digital services to learn more.

Our Services

get started

Ready to Chat?

We'd love to hear about your project and how we can help bring your ideas to life.

Let's Chat

© 2024 Glucode. All rights reserved.

get started

Ready to Chat?

We'd love to hear about your project and how we can help bring your ideas to life.

Let's Chat

© 2024 Glucode. All rights reserved.

get started

Ready to Chat?

We'd love to hear about your project and how we can help bring your ideas to life.

Let's Chat

© 2024 Glucode. All rights reserved.