Writing an Appium test in Kotlin
Tags: appium, tutorial, kotlin, automation
Published: 2020-04-27 23:59:39

---
title: Writing an Appium test in Kotlin
published: true
date: 2020-04-27 05:05:08 UTC
tags: Appium,Tutorial,Kotlin,automation
canonical_url: https://www.headspin.io/blog/appium/writing-an-appium-test-in-kotlin/
---
<p><a href="https://kotlinlang.org/" target="_blank" rel="nofollow noopener">Kotlin</a> is a modern programming language that focuses on conciseness, clarity, and code safety. Google officially adopted Kotlin by adding support into Android Studio in 2017 and since then has announced it as the preferred language for Android developers at Google I/O 2019. Perhaps your Android app team has incrementally added Kotlin code to your project or have elected to start new Android projects in Kotlin moving forward. Having the app code and UI automation code in the same language helps engineering and QA teams level set on the critical user journeys being tested. I’d like to share the basics of getting started with writing an <a href="https://headspin.io/appium" target="_blank" rel="nofollow noopener">Appium</a> test in Kotlin. I’ll be using the <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.magazines" target="_blank" rel="nofollow noopener">Google News Android app</a> as the target for this example and test on a real Google Pixel 3 XL from the <a href="https://www.headspin.io/platform" target="_blank" rel="nofollow noopener">HeadSpin</a> platform.</p>
<p>Kotlin is fully compatible with Java so we can fortunately leverage the Appium Java client and JUnit libraries in addition to writing our code in the IntelliJ IDE. IntelliJ has a free community version called IntelliJ IDEA CE, which can be downloaded from their <a href="https://www.jetbrains.com/idea/download/" target="_blank" rel="nofollow noopener">website</a> or via your package manager.</p>
</div>
				</div>
				</div>
				<div data-id="faba942" data-element_type="widget" data-widget_type="heading.default">
				<div>
			<h3>Getting started</h3> </div>
				</div>
				<div data-id="254121c" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>In IntelliJ IDE, navigate to <em>File &gt; New Project</em>. Select <em>Gradle</em> and under <em>Additional Libraries and Frameworks</em> select <em>Kotlin/JVM</em>. </p></div>
				</div>
				</div>
				<div data-id="244ad1f" data-element_type="widget" data-widget_type="image.default">
				<div>
					<div>
										<img width="1024" height="573" src="https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-1024x573.png" alt="" srcset="https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-1024x573.png 1024w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-300x168.png 300w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-768x430.png 768w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-1536x860.png 1536w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-2048x1146.png 2048w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-150x85.png 150w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-600x336.png 600w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-750x420.png 750w, https://www.headspin.io/wp-content/uploads/2020/04/KotlinJVM-1140x638.png 1140w" sizes="(max-width: 1024px) 100vw, 1024px"> </div>
				</div>
				</div>
				<div data-id="46c40a0" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>In the Project file view on the left, open the <em>build.gradle</em> file and add the following dependencies:</p></div>
				</div>
				</div>
				<div data-id="f075799" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><pre spellcheck="false">testCompile group: 'junit', name: 'junit', version: '4.13'
compile group: 'io.appium', name: 'java-client', version: '7.3.0'</pre></div>
				</div>
				</div>
				<div data-id="0061b51" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>We will add the Appium tests in the <em>src/test/kotlin</em> project directory.</p></div>
				</div>
				</div>
				<div data-id="3174478" data-element_type="widget" data-widget_type="image.default">
				<div>
					<div>
										<img width="656" height="874" src="https://www.headspin.io/wp-content/uploads/2020/04/Kotlin-file-structure.png" alt="" srcset="https://www.headspin.io/wp-content/uploads/2020/04/Kotlin-file-structure.png 656w, https://www.headspin.io/wp-content/uploads/2020/04/Kotlin-file-structure-225x300.png 225w, https://www.headspin.io/wp-content/uploads/2020/04/Kotlin-file-structure-600x799.png 600w" sizes="(max-width: 656px) 100vw, 656px"> </div>
				</div>
				</div>
				<div data-id="a08026b" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div>
<p>Right click the <em>kotlin</em> subdirectory and select <em>New &gt; Kotlin File/Class</em>. Create three new classes:</p>
<ul>
<li><em>ProjectCapabilities</em></li>
<li><em>TestBase</em></li>
<li><em>GoogleNewsAndroidTest</em></li>
</ul>
</div>
				</div>
				</div>
				<div data-id="acea31e" data-element_type="widget" data-widget_type="image.default">
				<div>
					<div>
										<img width="690" height="384" src="https://www.headspin.io/wp-content/uploads/2020/04/New-Kotline-File-.png" alt="" srcset="https://www.headspin.io/wp-content/uploads/2020/04/New-Kotline-File-.png 690w, https://www.headspin.io/wp-content/uploads/2020/04/New-Kotline-File--300x167.png 300w, https://www.headspin.io/wp-content/uploads/2020/04/New-Kotline-File--600x334.png 600w" sizes="(max-width: 690px) 100vw, 690px"> </div>
				</div>
				</div>
				<div data-id="99f7d6d" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>We will structure the project in these three classes to make the organization clear. The <em>ProjectCapabilities</em> class will return the Desired Capabilities, <em>TestBase</em> will be a base class for our test for scaffolding the test setup and teardown, and lastly the <em>GoogleNewsAndroidTest</em> class will inherit from our <em>TestBase</em>, use the Desired Capabilities, and contain our test logic.</p></div>
				</div>
				</div>
				<div data-id="1b6777e" data-element_type="widget" data-widget_type="heading.default">
				<div>
			<h3>1. ProjectCapabilities Class</h3> </div>
				</div>
				<div data-id="bbcbd07" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>Let’s get started with the ProjectCapabilities class. This class will have a method to return the Desired Capabilities.</p></div>
				</div>
				</div>
				<div data-id="dc72e8f" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><pre spellcheck="false">import org.openqa.selenium.remote.DesiredCapabilities

class ProjectCapabilities {
    companion object {
        fun AndroidBaseCapabilities(): DesiredCapabilities {
            val caps = DesiredCapabilities()
            caps.setCapability("autoAcceptAlerts", true)
            caps.setCapability("platformName", "Android")
            caps.setCapability("automationName", "UiAutomator2")
            caps.setCapability("deviceName", "8ABY0H6YG")
            caps.setCapability("udid", "8ABY0H6YG")
            caps.setCapability("appPackage", "com.google.android.apps.magazines")
            caps.setCapability("appActivity", "com.google.apps.dots.android.app.activity.CurrentsStartActivity")
            return caps
        }
    }
}</pre></div>
				</div>
				</div>
				<div data-id="c3e6214" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div>
<p>Functions and Methods in Kotlin are declared with the “fun” keyword. You can also indicate the function return type with a colon followed by the type. We can make this a static class method by declaring it in a “companion object.” You can create read-only variables with “val” and variables that can be reassigned with “var”.</p>
<p>In this case I am targeting a real Pixel 3 XL device in the HeadSpin platform. From the HeadSpin Web UI you can get the minimum Desired Capabilities for the device by clicking on the vertical dots menu and selecting Automation Configuration.</p>
</div>
				</div>
				</div>
				<div data-id="406a776" data-element_type="widget" data-widget_type="image.default">
				<div>
					<div>
										<img width="1024" height="407" src="https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-1024x407.png" alt="" srcset="https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-1024x407.png 1024w, https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-300x119.png 300w, https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-768x306.png 768w, https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-1536x611.png 1536w, https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-2048x815.png 2048w, https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-600x239.png 600w, https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-750x298.png 750w, https://www.headspin.io/wp-content/uploads/2020/04/HeadSpin-Device-Interface-1140x454.png 1140w" sizes="(max-width: 1024px) 100vw, 1024px"> </div>
				</div>
				</div>
				<div data-id="3547401" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>For the appPackage and appActivity I am specifying the associated values for the Google News Android app.</p></div>
				</div>
				</div>
				<div data-id="783e321" data-element_type="widget" data-widget_type="heading.default">
				<div>
			<h3>2. TestBase Class</h3> </div>
				</div>
				<div data-id="2806295" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div>
<p>Next, let’s work on our TestBase class. By default classes in Kotlin are implicitly final and can’t be inherited. To make a class inheritable, we’ll mark it with the “open” keyword. In this class we will create property variables for the: driver, capabilities, HeadSpin API Token, and WebDriver URL. We’ll provide visibility modifiers to our properties, in this case:</p>
<ul>
<li>
<u>Protected</u>: Only visible in the class or subclasses</li>
<li>
<u>Private</u>: Only visible in the class</li>
</ul>
<p>We’ll also mark our Desired Capabilities variable as “open” so it can be overridden from our GoogleNewsAndroidTest class which inherits from the TestBase class.</p>
<p>In addition you can indicate whether a variable can be null. The ability to declare this upfront is a great feature of the Kotlin language because it protects against unexpected NullPointerExceptions from our code. In this case we can indicate that the driver and caps can be null with “?” after the type and and set them to null. Kotlin also supports string interpolation by using the “$” character to interpolate a variable or “${}” to interpolate an expression. We’ll use this convenient language feature to pass our HeadSpin API Token to our WebDriver URL string.</p>
<p>Our TestBase will also have two JUnit annotations: @Before for our setup function and @After for our teardown to perform a driver quit. Our setup function will be straightforward and it will instantiate the driver object. In our teardown function we’ll check to see if the driver object is not null and if so quit our session. Otherwise we will throw an Exception. Kotlin provides a convenience operator for checking for a null condition with “?:”. This is called the Elvis Operator because if you turn your head sideways the question mark character looks like a swoosh of hair and the colon looks like eyes.</p>
</div>
				</div>
				</div>
				<div data-id="29d08df" data-element_type="widget" data-widget_type="image.default">
				<div>
					<div>
										<img width="458" height="514" src="https://www.headspin.io/wp-content/uploads/2020/04/rockstar.png" alt="" srcset="https://www.headspin.io/wp-content/uploads/2020/04/rockstar.png 458w, https://www.headspin.io/wp-content/uploads/2020/04/rockstar-267x300.png 267w" sizes="(max-width: 458px) 100vw, 458px"> </div>
				</div>
				</div>
				<div data-id="9d6bd3c" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>Do you see the resemblance now? Haha either way, the source code for the class can be found below and let’s carry on.</p></div>
				</div>
				</div>
				<div data-id="7ac645c" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><pre spellcheck="false">import io.appium.java_client.MobileElement
import io.appium.java_client.android.AndroidDriver
import org.junit.After
import org.junit.Before
import org.openqa.selenium.remote.DesiredCapabilities
import java.lang.Exception
import java.net.URL

open class TestBase {
    protected var driver: AndroidDriver&lt;MobileElement&gt;? = null
    protected open var caps: DesiredCapabilities? = null
    private val headSpinAPIToken: String = "your-api-token-here"
    private val webDriverURL: URL = URL("https://appium-dev.headspin.io/v0/$headSpinAPIToken/wd/hub")

    @Before
    fun setUp() {
        this.driver = AndroidDriver(webDriverURL, caps)
    }

    @After
    fun tearDown() {
        this.driver?.quit() ?: throw Exception("Driver instance was unable to quit.")
    }

}</pre></div>
				</div>
				</div>
				<div data-id="2870d5b" data-element_type="widget" data-widget_type="heading.default">
				<div>
			<h3>3. GoogleNewsAndroidTest Class
</h3> </div>
				</div>
				<div data-id="ea682cb" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>Our last class, GoogleNewsAndroidTest will have our test logic. Here we have one test function annotated with the JUnit Test annotation. Our test will be simple and straightforward, we will tap on the Headlines tab button and then scroll down from the list of news articles. Since we will be performing driver actions we’ll need to first ensure the driver is not null. Kotlin provides a way to perform an operation only if the value is not null using the “?” (the safe call operator) together with “let.”</p></div>
				</div>
				</div>
				<div data-id="1628dac" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><pre spellcheck="false">import io.appium.java_client.MobileBy
import org.junit.Test
import org.openqa.selenium.interactions.Interaction
import org.openqa.selenium.interactions.PointerInput
import org.openqa.selenium.interactions.Sequence
import org.openqa.selenium.remote.DesiredCapabilities
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait
import java.time.Duration

class GoogleNewsAndroidTest: TestBase() {
    override var caps: DesiredCapabilities? = ProjectCapabilities.AndroidBaseCapabilities()
    private val headlinesTabButton: String = "com.google.android.apps.magazines:id/tab_headlines"

    @Test
    fun headlinesScrollTest() {

        // Set an explicit wait of 10 seconds
        val wait = WebDriverWait(driver?.let { it }, 10)

        // Tap on the Headlines tab button
        wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.id(headlinesTabButton))).click()

        // Scroll Down
        val finger: PointerInput = PointerInput(PointerInput.Kind.TOUCH, "finger")
        val moveToStart: Interaction = finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), 726, 2452)
        val pressDown: Interaction = finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg());
        val moveToEnd: Interaction = finger.createPointerMove(Duration.ofMillis(1000), PointerInput.Origin.viewport(), 726, 660)
        val pressUp: Interaction = finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg())

        val swipe = Sequence(finger, 0)
        swipe.addAction(moveToStart)
        swipe.addAction(pressDown)
        swipe.addAction(moveToEnd)
        swipe.addAction(pressUp)

        driver?.let { it.perform(arrayListOf(swipe)) }

    }
}</pre></div>
				</div>
				</div>
				<div data-id="95bb0bc" data-element_type="widget" data-widget_type="heading.default">
				<div>
			<h3>Conclusion
</h3> </div>
				</div>
				<div data-id="e8927c9" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>Our work here is done! We can now execute our test and watch it in action.</p></div>
				</div>
				</div>
				<div data-id="ae8492e" data-element_type="widget" data-widget_type="image.default">
				<div>
					<div>
										<img width="1024" height="260" src="https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-1024x260.png" alt="" srcset="https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-1024x260.png 1024w, https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-300x76.png 300w, https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-768x195.png 768w, https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-1536x389.png 1536w, https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-600x152.png 600w, https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-750x190.png 750w, https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest-1140x289.png 1140w, https://www.headspin.io/wp-content/uploads/2020/04/GoogleNewsAndroidTest.png 1688w" sizes="(max-width: 1024px) 100vw, 1024px"> </div>
				</div>
				</div>
				<div data-id="0f9355d" data-element_type="widget" data-widget_type="text-editor.default">
				<div>
					<div><p>Congratulations you now have a taste of what it’s like to write an Appium test in Kotlin! If this article has helped further your knowledge feel free to Like or Share it. You can download the full project source code <a href="https://www.dropbox.com/s/xhhi100powwcbj2/Nathan%20-%20KotlinAppiumReference.zip?dl=0" target="_blank" rel="nofollow noopener">here</a>.</p></div>
				</div>
				</div>
						</div>
			</div>
		</div>
						</div>
			</div>
		</section>

The post [Writing an Appium test in Kotlin](https://www.headspin.io/blog/appium/writing-an-appium-test-in-kotlin/) appeared first on [HeadSpin](https://www.headspin.io).