<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alexander Kroll</title>
    <description>The latest articles on DEV Community by Alexander Kroll (@alexkroll).</description>
    <link>https://dev.to/alexkroll</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F918086%2Ffa9209d1-60a7-48f3-8a79-69656b1f6c02.png</url>
      <title>DEV Community: Alexander Kroll</title>
      <link>https://dev.to/alexkroll</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexkroll"/>
    <language>en</language>
    <item>
      <title>Building and running Flutter mobile applications for Android on AWS Device Farm</title>
      <dc:creator>Alexander Kroll</dc:creator>
      <pubDate>Mon, 06 Mar 2023 21:28:16 +0000</pubDate>
      <link>https://dev.to/alexkroll/building-and-running-flutter-mobile-applications-for-android-on-aws-device-farm-4f14</link>
      <guid>https://dev.to/alexkroll/building-and-running-flutter-mobile-applications-for-android-on-aws-device-farm-4f14</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;This article will give you an overview on how to build and run a Flutter cross-platform mobile application for the Android OS platform that is deployed and tested on several devices in the AWS Device Farm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting the scene
&lt;/h2&gt;

&lt;p&gt;When building and testing mobile applications and in case you want to assure that your mobile application is running correctly on different devices and operating systems, this can be very cumbersome and expensive over time. The efforts for various tasks of the device management like maintaining the physical infrastructure, patching and updating the devices can be very cost intensive for a company in case these tasks must be conducted by a developer or someone else in a business organization. Just imagine you have 15 or 20 different devices, that need to get patched manually. This will take a few hours in case everything works fine. The effort for maintenance will increase linearly, depending on the number of managed devices. And not only the different devices are important but also the combinations of devices and installed operating versions could let explode the test efforts dramatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Device Farm to the rescue
&lt;/h2&gt;

&lt;p&gt;But there is a solution. AWS Device Farm to the rescue. AWS offers with AWS Device Farm a solution that makes mobile testing a breeze. AWS Device Farm is a managed service on AWS that allows using a fleet of mobile devices and mobile environments from AWS via an on-demand model to either provision devices for manual or automated testing.&lt;br&gt;
The good news, you can test AWS Device Farm and get the first 1000 minutes for free.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;What you will need for the sample is the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Android Studio&lt;/li&gt;
&lt;li&gt;Android SDK&lt;/li&gt;
&lt;li&gt;Flutter (Version 3.0.5 or higher)&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;AWS Account&lt;/li&gt;
&lt;li&gt;Some free space on your SSD ;-)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Flutter sample app
&lt;/h2&gt;

&lt;p&gt;The Flutter sample app for the test is a simplistic login page with username and password that forwards to a welcome screen page. From there you can start a browser application with a search engine web page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ry_Q3Iz7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/alkwwzhxa0savuilq3fv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ry_Q3Iz7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/alkwwzhxa0savuilq3fv.png" alt="Image description" width="714" height="422"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Testing with Appium
&lt;/h2&gt;

&lt;p&gt;Appium is a common open-source test automation framework for use with native, hybrid and mobile web apps. It uses the Webdriver protocol (similar like Selenium) and can be used for testing iOS, Android and Windows apps.&lt;br&gt;
Appium is one of the test frameworks which is directly supported by the AWS Device Farm.&lt;br&gt;
For more information: &lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/devicefarm/latest/developerguide/test-types-appium.html"&gt;https://docs.aws.amazon.com/devicefarm/latest/developerguide/test-types-appium.html&lt;/a&gt;&lt;br&gt;
With Appium you can use specific annotations like “AndroidFindBy” to identify elements on a screen of a mobile app, interact with these elements (clicking, entering text, ...) and checking the state of these elements (e. g. is shown or is enabled). This can be done with several programming languages, like Java, Kotlin, Python, JavaScript, etc.&lt;/p&gt;

&lt;p&gt;Here some examples with Java.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// identifying elements with annotations&lt;/span&gt;
&lt;span class="nd"&gt;@AndroidFindBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"LoginText"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MobileElement&lt;/span&gt; &lt;span class="n"&gt;loginText&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// identifying elements programmatically&lt;/span&gt;
&lt;span class="nc"&gt;MobileElement&lt;/span&gt; &lt;span class="n"&gt;loginText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElementByAccessibilityId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LoginText"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// perform a click&lt;/span&gt;
&lt;span class="n"&gt;loginText&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// enter text&lt;/span&gt;
&lt;span class="n"&gt;loginText&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// asking if element is shown or not&lt;/span&gt;
&lt;span class="n"&gt;loginText&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For writing Appium tests in Java you can also choose between different testing frameworks, like JUnit or TestNG.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write Appium tests for AWS Device Farm
&lt;/h2&gt;

&lt;p&gt;There is a sample app for the AWS Device Farm which illustrates what you need for you Appium tests on the AWS Device Farm.&lt;br&gt;
See &lt;a href="https://github.com/aws-samples/aws-device-farm-appium-tests-for-sample-app"&gt;https://github.com/aws-samples/aws-device-farm-appium-tests-for-sample-app&lt;/a&gt;&lt;br&gt;
One important step is to create a ZIP file with all compiled Appium tests, and their dependencies (Appium jars) needed to execute the tests. This ZIP file will be later uploaded in the AWS Device Farm together with the APP binary.&lt;br&gt;
The recommended way to implement the tests is to make use of the page pattern, which creates a “shadowed” object of the mobile frontend page. The test can make use of the Appium features to identify Android application elements like the input fields and the button by using the @AndroidFindBy annotation with an XPath expression in the object tree and will provide that object as a MobileElement. In addition, you can now configure the possible actions of the page by using public methods to modify the contents of the MobileElements and trigger send actions on the button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.alex.flutter_sample.appium.pages&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.appium.java_client.AppiumDriver&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.appium.java_client.MobileElement&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.appium.java_client.pagefactory.AndroidFindBy&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginPage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BasePage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@AndroidFindBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xpath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.EditText[1]"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MobileElement&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@AndroidFindBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xpath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.EditText[2]"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MobileElement&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@AndroidFindBy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessibility&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Login"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MobileElement&lt;/span&gt; &lt;span class="n"&gt;loginButton&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;LoginPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AppiumDriver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MobileElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;loginButton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clear&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;clickLogin&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loginButton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sample Appium test could check if a user can go from the LoginPage to the SecondPage when authenticating with the correct credentials. To spin up this scenario, we would create an instance of the LoginPage and check, that the page is loaded successfully. Then the user input (username and password) is simulated and a click on the login button is triggered. This will cause a change of the page and we can assert that the SecondPage is displayed. In the end we could take a screenshot of the test run, that will be bundled with the test result of this test run and can be used for manual checks at a later point in time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;login_withCorrectCredentials_gotoSecondPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// given&lt;/span&gt;
    &lt;span class="nc"&gt;LoginPage&lt;/span&gt; &lt;span class="n"&gt;loginPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LoginPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loginPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// when&lt;/span&gt;
    &lt;span class="n"&gt;loginPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alex"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;loginPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"alex"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;loginPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;clickLogin&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// then&lt;/span&gt;
    &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SecondPage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;takeScreenshot&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"secondPage.png"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run automated Appium tests on AWS Device Farm
&lt;/h2&gt;

&lt;p&gt;The following steps are needed to setup a project in AWS Device Farm to run Appium tests.&lt;br&gt;
You need to create an AWS Device Farm project which is just an “organizational unit” containing a configuration of your application. So, you can simply start by creating a mobile application project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iQAdikRg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gaxj1tmfs8zw8tfwuxkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iQAdikRg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gaxj1tmfs8zw8tfwuxkf.png" alt="Image description" width="880" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can then see the project in the overview of your mobile projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m5YTNRqB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjsh1m65bouzbddeob1z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m5YTNRqB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qjsh1m65bouzbddeob1z.png" alt="Image description" width="880" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Within the project you can start the configuration of automated tests and start a new run. In this setup we want AWS Device Farm to spin up an Android application and run the Appium tests automatically once the device is ready. The other option here would be to provision a device for “remote access”. That would give you a “bare” device that you can use for various manual testing purposes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6kgRVZe8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xe2h7h2lylvylfnji0wj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6kgRVZe8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xe2h7h2lylvylfnji0wj.png" alt="Image description" width="880" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the project you have two options, what kind of project you want to test on the device. That could be a mobile application or a web application. In this guide we will focus on an Android mobile application that has been implemented with the Flutter framework. You need to upload an apk file (Android Package) and upload it AWS Device Farm. You can find your app-release.apk file in project-name/module-name/build/outputs/apk/ folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E4NSSC6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zf4twww7vgyou7gmei9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E4NSSC6Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zf4twww7vgyou7gmei9.png" alt="Image description" width="880" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the configuration section you have the option to choose between a standard environment setup and a custom environment setup. A custom setup can be very useful in case you have some special steps to perform before test execution. A typical use case for a custom environment could be the setting of a specific Appium version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1D9-h5Th--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jo3lfm2q0xo8dcbsh9c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1D9-h5Th--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jo3lfm2q0xo8dcbsh9c.png" alt="Image description" width="880" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to select some devices that can be used to run the mobile application. You have the possibility to choose between more than 100 devices and you can group device to a device pool, that can be reused. I selected a list of different devices from different vendors like Samsung and Google. In general, the availability of Samsung devices is very good while other vendors like Huawei are not available. I recommend testing the application also on different versions of the Android operating systems in combination with different devices. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SWUIIcDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ay5d7aely75bpirkc8is.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SWUIIcDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ay5d7aely75bpirkc8is.png" alt="Image description" width="880" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case you want to load specific data on to the device, there is an upload possibility. In addition, you can specify the network settings of the device, the geo location for the test run. This can be useful in case you have scenarios where a geo location is relevant as you have a location-based service using a map or in case you want to test your application with a bad internet connection with a high latency or low bandwidth. For this case you could also create a network profile. When running a multi-market or multi-language application it could also be useful to have some variations on the locale settings. So, AWS Device Farm offers you a wide bandwidth of parameters ton change the desired state of the device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2WE2ovyi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vc4txioe47z0qxo33vvf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2WE2ovyi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vc4txioe47z0qxo33vvf.png" alt="Image description" width="880" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After setting the device state you can start the automated test runs and will then see an overview of the automated test for your application. Some minutes later you can see the result of the test as a circle diagram, indicating the success rate of the executed tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YAyw72XN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h95yqyrcq8ildox4ak0x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YAyw72XN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h95yqyrcq8ildox4ak0x.png" alt="Image description" width="880" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the test has been performed you can see the jobs, that have been run and can drill down into the details of the test run. Typically, it takes about 2-3 minutes until the execution of the tests starts, as this time is needed to select and prepare a device in the AWS Device Farm for you. After this preparation time your automated tests are executed on the specified device and after the execution, the device is shutdown. The result of the automated test run contains different artifacts like screenshots of the test workflow on the device, a short video of the workflow, the test specification log, the log output, and a very simplistic performance dashboard of the automated test run, giving a good indication of the CPU and memory usage during the test on the device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Ji947WI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tegzn1arbcuh72ze5q3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Ji947WI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tegzn1arbcuh72ze5q3a.png" alt="Image description" width="880" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LT6qvCsK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5w4og5ze6m577k1v6nah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LT6qvCsK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5w4og5ze6m577k1v6nah.png" alt="Image description" width="880" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UEpm_laV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5bhh4ogptbb42juve18j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UEpm_laV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5bhh4ogptbb42juve18j.png" alt="Image description" width="880" height="454"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup AWS Device Farm project from CLI
&lt;/h2&gt;

&lt;p&gt;In case you do not want to do all the steps manually, it may be more efficient to make use of the AWS CLI which allows you to perform all the necessary steps from a shell script. Especially, when you want to use a CI/CD tool like Jenkins, Gitlab, and others, these scripted steps might be useful for reuse within some pipeline jobs or steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#! /bin/bash&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Starting automatic deployment of Alex Sample App with Tests"&lt;/span&gt;

&lt;span class="c"&gt;# 1. Retrieve PROJECT_ARN&lt;/span&gt;

PROJECT_NAME &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Alex Sample Project"&lt;/span&gt;
PROFILE &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"alex.dev"&lt;/span&gt;
REGION &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
PROJECT_ARN &lt;span class="o"&gt;=&lt;/span&gt; aws devicefarm create-project &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_NAME&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PROFILE &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt; | jq &lt;span class="s1"&gt;'.project.arn'&lt;/span&gt;

&lt;span class="c"&gt;# 2. Get Upload ARN and URL for Android App&lt;/span&gt;

APP_FILE &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"app-release.apk"&lt;/span&gt;
APP_TYPE &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ANDROID_APP"&lt;/span&gt;
APP_UPLOAD_JSON &lt;span class="o"&gt;=&lt;/span&gt; aws devicefarm create-upload –project-arn &lt;span class="nv"&gt;$PROJECT_ARN&lt;/span&gt; –name &lt;span class="nv"&gt;$APP_FILE&lt;/span&gt; –type &lt;span class="nv"&gt;$APP_TYPE&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PROFILE&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt; | jq &lt;span class="s1"&gt;'.upload'&lt;/span&gt;
APP_UPLOAD_ARN &lt;span class="o"&gt;=&lt;/span&gt; jq &lt;span class="s1"&gt;'.arn'&lt;/span&gt; &lt;span class="nv"&gt;$APP_UPLOAD_JSON&lt;/span&gt;
APP_UPLOAD_URL &lt;span class="o"&gt;=&lt;/span&gt; jq &lt;span class="s1"&gt;'.url'&lt;/span&gt; &lt;span class="nv"&gt;$APP_UPLOAD_JSON&lt;/span&gt;

&lt;span class="c"&gt;# 3. Upload the app&lt;/span&gt;

curl &lt;span class="nt"&gt;-T&lt;/span&gt; app-release.apk &lt;span class="nv"&gt;$APP_UPLOAD_URL&lt;/span&gt;

&lt;span class="c"&gt;# 4. Get Upload ARN and URL for Test App&lt;/span&gt;

TEST_FILE &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tests.zip"&lt;/span&gt;
TEST_TYPE &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"TEST_TYPE"&lt;/span&gt;
TEST_UPLOAD_JSON &lt;span class="o"&gt;=&lt;/span&gt; aws devicefarm create-upload –project-arn &lt;span class="nv"&gt;$PROJECT_ARN&lt;/span&gt; –name &lt;span class="nv"&gt;$TEST_FILE&lt;/span&gt; –type &lt;span class="nv"&gt;$TEST_TYPE&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PROFILE&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt; | jq &lt;span class="s1"&gt;'.upload'&lt;/span&gt;
TEST_UPLOAD_ARN &lt;span class="o"&gt;=&lt;/span&gt; jq &lt;span class="s1"&gt;'.arn'&lt;/span&gt; &lt;span class="nv"&gt;$TEST_UPLOAD_JSON&lt;/span&gt;
TEST_UPLOAD_URL &lt;span class="o"&gt;=&lt;/span&gt; jq &lt;span class="s1"&gt;'.url'&lt;/span&gt; &lt;span class="nv"&gt;$TEST_UPLOAD_JSON&lt;/span&gt;

&lt;span class="c"&gt;# 5. Upload the tests&lt;/span&gt;

curl &lt;span class="nt"&gt;-T&lt;/span&gt; tests.zip &lt;span class="nv"&gt;$TEST_UPLOAD_URL&lt;/span&gt;

&lt;span class="c"&gt;# 6. Create device pool&lt;/span&gt;

DEVICE_POOL_NAME &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SampleDevicePool"&lt;/span&gt;
DEVICE_POOL_ARN &lt;span class="o"&gt;=&lt;/span&gt; aws devicefarm create-device-pool –project-arn &lt;span class="nv"&gt;$PROJECT_ARN&lt;/span&gt; –name &lt;span class="nv"&gt;$DEVICE_POOL_NAME&lt;/span&gt; –rules &lt;span class="s1"&gt;'[{"attribute": "PLATFORM", "operator": "EQUALS", "value": ""ANDROID""}]'&lt;/span&gt;  &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PROFILE&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt; | jq &lt;span class="s1"&gt;'.devicePool'&lt;/span&gt;

&lt;span class="c"&gt;# 7. Schedule test run&lt;/span&gt;

SCHEDULE_RUN_NAME &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Sample-Test-Run"&lt;/span&gt;
TEST_RUN_RESULT &lt;span class="o"&gt;=&lt;/span&gt; aws devicefarm schedule-run –project-arn &lt;span class="nv"&gt;$PROJECT_ARN&lt;/span&gt; –app-arn &lt;span class="nv"&gt;$APP_UPLOAD_ARN&lt;/span&gt; –device-pool-arn &lt;span class="nv"&gt;$DEVICE_POOL_ARN&lt;/span&gt; –name &lt;span class="nv"&gt;$SCHEDULE_RUN_NAME&lt;/span&gt; –test &lt;span class="s1"&gt;'{"type": "TEST_TYPE","testPackageArn":"'&lt;/span&gt; + &lt;span class="nv"&gt;$TEST_UPLOAD_ARN&lt;/span&gt; + &lt;span class="s1"&gt;'"}'&lt;/span&gt;  &lt;span class="nt"&gt;--profile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PROFILE&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$REGION&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TEST_RUN_RESULT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This article has come to an end, and you now have a blueprint and hopefully a good feeling on how to test a Flutter application automatically on AWS Device Farm.&lt;br&gt;
My experience with the AWS Device Farm and Android mobile applications was quite nice. The UI of AWS Device Farm is simple but contains the most important features to modify the state of the devices and supports the relevant testing frameworks. Most of the actual devices on the market are available within 2 to 6 weeks after their market release. My observation is that the support for some device manufacturers is really good (Samsung, Apple, Google), while some other manufacturers like Huawei are not widely supported. But in case you need some very specific devices you can always make use of the "private devices" features which is a BYOD model (bring your own device).&lt;/p&gt;

</description>
      <category>aws</category>
      <category>flutter</category>
      <category>android</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
