Automating Flutter Apps Using Appium Flutter Driver With Java

Automating Flutter Apps Using Appium Flutter Driver With Java

Mobile users worldwide have been constantly increasing over the recent years. Mobile applications have enabled the delivery of daily-use goods to luxury commodities at the customers’ doorstep.

As per Statista, mobile app downloads increased to 255 billion in 2022, up by more than 80 percent from 140.7 billion app downloads in 2016. Users downloaded almost 77 billion mobile applications worldwide during the first half of 2023.

The growing demand for mobile applications necessitates continuous development of robust frameworks that enable quick and adaptable mobile app creation, keeping pace with rapidly evolving business needs.

There are many native mobile application development frameworks, like React Native, Ionic, Xamarin, Swift, etc., that are popular and trending in the market. Flutter is the latest addition to these frameworks that support building cross-platform application development. As shown below, Flutter has gained immense popularity compared to other cross-platform mobile app testing frameworks available in the market!

Learn why Python is the top choice for automation testing. This comprehensive tutorial provides a step-by-step guide to Python automation testing to help you streamline your testing process.

Source

For faster feedback on the build quality, it is recommended to perform automation testing as it can provide accurate results on executing the same tests multiple times.

In this Appium testing tutorial, we will learn to test the Flutter mobile application using the Appium Flutter Driver with Java. We will also deep dive into installing Flutter, using Inspector, and writing mobile automation tests using Appium.

What is Flutter?

Flutter is Google’s cross-platform open-source mobile development framework for developing Android and iOS applications using a single code base. Introduced in May 2017, it is a comprehensive framework encompassing widgets, a rendering engine, testing and integration tools, and APIs. This all-inclusive framework empowers developers to build and deploy mobile applications effortlessly.

Since its launch, it has proven to be a great cross-platform framework that can be used to develop high-quality applications that look like native Android and iOS apps. Examples of applications built using Flutter include Google, Alibaba, and many others.

Flutter is a convenient toolkit that is easy for creating animations and high-quality UI components. It has 250.9K followers over X (earlier Twitter), 160K Stars on GitHub, and 124K followers on Reddit. When writing this blog, the latest version of Flutter is 3.16.

Different types of mobile applications

There are three different types of mobile applications:

  • Native mobile app

  • Mobile web app

  • Hybrid mobile app

What are native mobile applications?

Native mobile applications are developed specifically for the phone’s operating system. Almost 98% of the phones run on either Android or iOS. These applications are installed on the device and store the data on it. These applications have access to essential phone peripherals like cameras, GPS, microphones, and more.

While developing native Android applications, developers commonly use languages like Kotlin or Java, while the development of iOS applications typically involves languages such as Swift and Objective-C. Some native mobile applications include the Calculator app, Google Maps, and popular games like Pokémon GO.

Test your native app and website on real iOS and Android devices hosted on the cloud. LambdaTest is a convenient, cost-effective and centralised solution for running realtime mobile testing platform with real devices cloud.

What are mobile web applications?

Mobile web applications are web applications that are optimized for mobile screen(s). They are websites written in HTML/CSS, run by a browser, and aren’t mobile applications.

These applications don’t need to be downloaded and installed on the phone. It can access a limited amount of the device’s native features and information like geolocation, media, etc. Examples of mobile web applications include the Uber app and shopping websites like amazon.com. These websites can run on the mobile browser and perform all the functions like a mobile application.

What are hybrid mobile applications?

Hybrid applications combine elements of both Native and Web applications. The core application is built using web technologies like HTML, CSS, and JavaScript and then wrapped within a native application.

The app is run within a native application and its embedded browser rather than being shown using a mobile browser. An Android application uses the WebView element to display the app, while the iOS application uses the WKWebView for the same function.

In short, Hybrid Mobile app = Native app + Mobile Web app. Examples of Hybrid applications include Facebook, Twitter, LinkedIn and Instagram.

Testing Flutter applications v/s Native applications

Assessing native applications is straightforward, thanks to the availability of tools and frameworks designed for conducting unit testing on these applications.

The Espresso framework by Android can be used to test native Android applications. Similarly, the XCTest framework can be used to test iOS applications. Over and above these frameworks, other mobile app testing tools like WebdriverIO and Appium are popular and used for testing mobile applications thoroughly. Recently, Appium released a 2.0 version with more advanced features, making it a more robust framework.

For testing the Flutter app, the flutter_driver that comes pre-installed with Flutter SDK can be used to write automated tests. However, the problem in using flutter_driver is that the test engineer should be well versed in Dart programming language to write tests using flutter_driver.

Flutter applications can be automated using the Appium Flutter Driver, developed by the Appium community. With the Appium Flutter Driver, there is no need to get exposure to the Dart programming language. The automation tests of the Flutter application can be written in Java, JavaScript, Python, etc., the languages supported by the Appium framework.

Learn why Python is the top choice for automation testing. This comprehensive tutorial provides a step-by-step guide to Python automation testing to help you streamline your testing process.

To automate any mobile application, we need to locate the selectors that can be used to locate the mobile elements on the application and interact with them. The Appium Inspector tool cannot be used to find the Flutter application’s selectors.

The Flutter Widget Inspector tool can visualize and explore Flutter widget trees and help understand the existing layouts. We will also require help from developers and ask them to add the respective locators in the application so that they can be used in the automated tests to interact easily with the mobile elements.

The following is a summarized list that shows the difference between testing the Native and Flutter applications:

Let’s dive deep into how to perform automated Flutter testing using the Appium Flutter Driver with Java.

Getting started with Flutter

As we learned in the earlier section of this blog on using Appium Flutter Driver with Java, Appium Inspector cannot inspect and locate the Flutter application’s mobile elements. Hence, we need a Flutter Widget Inspector for it.

In this section, we will learn about downloading and installing Flutter SDK. Next, we will check out a Flutter sample app and update the required settings in Android Studio. Finally, we will run the Flutter app on the Android emulator and check out the Flutter Widget Inspector.

We need access to the Flutter application’s code base for running the Flutter Widget Inspector. The following steps will help us install Flutter on the local machine.

Downloading and Installing Flutter SDK

You can download Flutter SDK from Flutter’s official website for Windows, macOS, Linux, and ChromeOS platforms.

I am currently using macOS, so I will be clicking on the macOS box and navigating to the download page for further installation steps on macOS.

On the macOS installation details page, I will select and download the Apple Silicon zip file, as I currently use the Macbook Pro with an M2 chip. Another zip file for Macs with Intel chips can also be used.

Once the zip file is downloaded, we must perform the following steps to install Flutter SDK on the local machine:

  1. Extract the downloaded zip file.

  2. Setting the Environment variable for Flutter.

  3. Run Flutter Doctor.

Explore the Top 17 Programming for Automation testing Languages in 2024.

Cloning the Flutter sample mobile app

With the help of the following command, the Flutter sample repository can be cloned.

git clone git@github.com:flutter/samples.git

Opening the Flutter sample application in Android Studio

The Provider Shopper sample Flutter application will be used for test automation.

Open the project in the Android Studio app after the successful cloning of the sample project repository is complete.

Adding the Flutter plugin to Android Studio

The Flutter plugin needs to be added to Android Studio as it helps compile and run the Flutter app. The Flutter plugin can be installed using the Android Studio >> Settings >> Plugins menu.

Setting the Flutter SDK path in Android Studio

Note: The Flutter SDK includes the full Dart SDK and has the Dart command-line interface in its bin folder.

Once Flutter SDK is configured, Dart SDK will be auto-configured.

Updating the dev dependencies in the pubspec.yml file

The dev_dependencies for flutter_test, test, and flutter_driver need to be added in the pubspec.yml file.

dev_dependencies:
 test: any
 flutter_test:
   sdk: flutter
 flutter_driver:
   sdk: flutter

The below screenshot of the pubspec.yml file shows the additions of dev_dependencies.

Filename: pubspec.yml

Learn why Python is the top choice for automation testing. This comprehensive tutorial provides a step-by-step guide to Python automation testing to help you streamline your testing process.

Importing the dev dependencies

The dev_dependencies updated in the pubspec.yml need to be imported, which can be done using the following command:

flutter pub get

Updating the main.dart file

The following import statement needs to be added to the main.dart file for importing flutter_driver_extension.

import 'package:flutter_driver/driver_extension.dart';

The enableFlutterDriverExtension() method should be added in the main() method before the runApp statement in the main.dart file.

void main() {
    enableFlutterDriverExtension();
    runApp(MyApp());
 }

Below is the screenshot of the main.dart file after adding the code mentioned above statements:

Starting the Flutter Android application on the Android emulator

The Flutter application can be run on the Android emulator by using the following steps:

  1. Start the Android emulator.

  2. Select the Android emulator name from the dropdown box, click the Play button to build the Provider Shopper application locally, and run it on the selected emulator.

How to test Android Flutter applications using Appium Flutter Driver?

The following are the details about the technical stack used in this blog to automate the Flutter application using Appium Flutter Driver with Java.

The first step in automating any mobile application is to locate the mobile elements to perform the interactions on it. In the case of Flutter applications, the Flutter Widget Inspector, which comes as an inbuilt tool with Flutter, will be used to inspect elements. The Appium Inspector is incapable of locating the Flutter mobile elements.

Test your native app and website on real iOS and Android devices hosted on the cloud. LambdaTest is a convenient, cost-effective and centralised solution for running realtime and Automated test on online real device testing.

What is Flutter Widget Inspector?

Within the Flutter framework, Widgets serve as the fundamental building blocks. They encompass form controls like textboxes and buttons and layouts like centering, padding, and rows.

Flutter widget trees can be explored and visualized using the Flutter Widget Inspector. It helps in understanding existing layouts and diagnosing the layout issues.

Flutter Widget Inspector

The Flutter Inspector is a tool that helps explore and visualize the Flutter widget trees. It can help locate the selectors for the mobile elements used in the mobile automation tests. It can also be used to understand the existing layouts and diagnose related issues.

How to use Flutter Widget Inspector?

Flutter Widget Inspector can only be started after the local build is created and the Flutter application runs in the Emulator/Simulator. To showcase the work of Flutter Widget Inspector, we will be running the local build on an Android emulator.

Flutter Widget Inspector can be started by clicking on the Flutter Inspector toolbar on the extreme right of the Android Studio screen.

The Flutter Widget Inspector should open as shown in the screenshot below:

We need to follow the below steps to locate the mobile elements:

  1. Click on the Select Widget Mode button in Flutter Inspector.

  2. Navigate to the Android emulator and select the field for which the mobile element needs to be located.

Let’s locate the mobile element for the Username field of the Provider Shopper app by clicking on the Select Widget Mode button and selecting the Username field in the app. It will locate the mobile element for the Username field, and as shown in the screenshot below, it shows the mobile element as “TextFormField”.

However, if you notice, there is no key attached to it. Hence, it will be challenging to locate this field as we can see other elements for which the same element, “TextFormField,” is shown.

Need to convert BCD codes to Decimal quickly? Our BCD to Decimal Converter tool provides an easy way to convert BCD codes to Decimal. Try it now and save time.

Let’s add a key to the Username field to make it unique so we can locate it easily.

To add a key, we need to minimize the Flutter Widget Inspector window; just below it, we will notice the login.dart file is already open. This file houses all the elements and their respective properties for the login page.

Let’s add the key for the Username field by adding the following line of code:

key: const Key("username"),

Save the login.dart file after adding the key for the Username field.

Halt the locally running app, restart it, and build it locally. Then, utilize the Flutter Widget Inspector to confirm the successful addition of the key by inspecting the Username field.

We can also see that the key value “username” is displayed next to the TextFormField for Username.

Congratulations! The key for the Username field is successfully added and can be used as a locator for locating this field in the automation tests.

Let’s repeat the same steps for the Password field and update its key.

Update Key for Password field

Password Key updated successfully can be viewed in Flutter Widget Inspector

Next, we need to locate the mobile element for the ENTER button to click on it to log in to the application.

We will follow the same steps as we did for the Username and Password fields, but we will not be updating the key for this button; as we can see, it already has the mobile element — TEXT– with the value “Enter”. This can be used in automated tests for interacting with this button.

To run the Android automation tests, we would require the apk file to be generated. As we use Appium Flutter Driver with Java to interact with the app and run the automation tests, we must compile the build in debug or profile mode as Appium Flutter Driver does not support the apps in release mode.

Decode UTF8 encoded data with ease using our online UTF8 Decode tool now and simplify your workflow! Decode your data quickly and accurately.

Generating the build for Android and iOS

The following commands can be used to generate the Flutter app build in debug and profile mode for Android and debug, profile, and simulator mode for iOS.

Please make sure that before you run the command for generating the build, the local instance, if running, should be stopped by pressing the red Stop button on the toolbar.

The following command should be executed in the terminal for generating the Android build in debug mode:

flutter build apk --debug

Once the build generation is finished, the build output path will be printed in the console.

Let’s navigate to the path printed in the console and copy the apk file generated so we can use it in our automation tests.

Writing the automated tests for the Flutter app

The following are the summarized steps we did in the previous part of the blog before we wrote the automated tests using Appium Flutter Driver with Java:

  1. Configure the Flutter SDK.

  2. Set up the Flutter app project in Android Studio.

  3. Locate the mobile elements using Flutter Widget Inspector.

  4. Generate the Android build.

Finally, we are in the last stage of this blog on using Appium Flutter Driver with Java, where we will be writing the automated tests for the Provider Shopper — a sample app by Flutter. We will run the tests on the Samsung Galaxy S21 5G Real Device on the LambdaTest cloud grid that has Android 13 installed on it.

LambdaTеst is an AI-powered tеst orchеstration and еxеcution platform that allows you to perform Flutter app tеsting on a rеal dеvicе cloud both manually and automatically using tеsting framеworks such as Appium, Espresso, and XCUITеst.

Subscribe to the LambdaTest YouTube Channel and stay updated with the latest tutorials on mobile app testing, Appium automation, automation testing, and more.

The following test scenario will be automated in the app.

Test Scenario:

  1. Open the Provider Shopper sample app on the Samsung Galaxy S21 5G real device on LambdaTest Cloud grid

  2. On the Login Page, enter Username and Password.

  3. Click the ENTER button to log in to the app.

  4. Check that the title “Catalog” is displayed on the next page after successful login.

Need to encode your text into UTF-8 format? Use our UTF-8 Encode tool to encode your text for seamless communication across all platforms and devices. Try it for free today.

Login Page of Provider Shopper app

Catalog Page of Provider Shopper app

Implementation [Test Scenario]

Before implementing the test scenarios, we must download and install the Appium Flutter Driver. It can be installed using the terminal with the following command:

 appium driver install --source=npm appium-flutter-driver

With the installation of Appium Flutter Driver, we are now ready to start writing the test automation scripts for the Provider Shopper Flutter app.

A Maven project needs to be created, and the dependencies for Appium, Appium Flutter Finder, and TestNG should be added to the pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.github.mfaisalkhatri</groupId>
    <artifactId>flutter-lambdatest-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>flutter-lambdatest-demo</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <appium-java-client-version>9.0.0</appium-java-client-version>
        <testng.version>7.8.0</testng.version>
        <appium-flutterfinder-java.version>1.0.1</appium-flutterfinder-java.version>
        <lombok-version>1.18.30</lombok-version>
        <maven.compiler.version>3.11.0</maven.compiler.version>
        <java.release.version>17</java.release.version>
        <maven.surefire.version>3.2.2</maven.surefire.version>
        <maven.source.encoding>UTF-8</maven.source.encoding>
        <suite-xml>testng.xml</suite-xml>
        <argLine>-Dfile.encoding=UTF-8 -Xdebug -Xnoagent</argLine>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/io.appium/java-client -->
        <dependency>
            <groupId>io.appium</groupId>
            <artifactId>java-client</artifactId>
            <version>${appium-java-client-version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.testng/testng -->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.github.ashwithpoojary98</groupId>
            <artifactId>appium_flutterfinder_java</artifactId>
            <version>${appium-flutterfinder-java.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok-version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.version}</version>
                <configuration>
                    <release>${java.release.version}</release>
                    <encoding>${maven.source.encoding}</encoding>
                    <forceJavacCompilerUse>true</forceJavacCompilerUse>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven.surefire.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>test</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <useSystemClassLoader>false</useSystemClassLoader>
                    <properties>
                        <property>
                            <name>usedefaultlisteners</name>
                            <value>false</value>
                        </property>
                    </properties>
                    <suiteXmlFiles>
                        <suiteXmlFile>${suite-xml}</suiteXmlFile>
                    </suiteXmlFiles>
                    <argLine>${argLine}</argLine>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

Once the dependencies are updated in the pom.xml it is the time now to start with the configuration of Android Driver and its respective capabilities so we could run the tests on the Android device successfully. For setting the Android Driver and its capabilities, AndroidDriverManager class is created.

@Builder
public class AndroidDriverManager {

    private static final ThreadLocal<AndroidDriver> DRIVER = new ThreadLocal<>();

    private String buildName;
    private String testName;
    private Platform platform;
    private String platformVersion;
    private String deviceName;
    private String app;
    private static final String LT_USERNAME = System.getProperty("LT_USERNAME");
    private static final String LT_ACCESS_KEY = System.getProperty("LT_ACCESS_KEY");
    private static final String GRID_URL = "@mobile-hub.lambdatest.com/wd/hub";


    public AndroidDriverManager createAndroidDriver() {
        try {
            setDriver(new AndroidDriver(new URL(format("https://{0}:{1}{2}", LT_USERNAME, LT_ACCESS_KEY, GRID_URL)), setCapabilities()));
            setupBrowserTimeouts();

        } catch (MalformedURLException e) {
            throw new Error("Error while creating Android Driver Session");
        }
        return this;
    }

    public AndroidDriver getAndroidDriver() {
        return AndroidDriverManager.DRIVER.get();
    }

    public void quitDriver() {
        if (null != DRIVER.get()) {
            getAndroidDriver().quit();
            DRIVER.remove();
        }
    }

    private HashMap<String, Object> ltOptions() {
        final var ltOptions = new HashMap<String, Object>();
        ltOptions.put("username", LT_USERNAME);
        ltOptions.put("accessKey", LT_ACCESS_KEY);
        ltOptions.put("platformName", platform);
        ltOptions.put("deviceName", deviceName);
        ltOptions.put("platformVersion", platformVersion);
        ltOptions.put("app", app);
        ltOptions.put("automationName", "Flutter");
        ltOptions.put("build", buildName);
        ltOptions.put("name", testName);
        ltOptions.put("w3c", true);
        ltOptions.put("isRealMobile", true);
        ltOptions.put("autoGrantPermissions", true);
        ltOptions.put("plugin", "java-testNG");
        ltOptions.put ("visual", true);
        ltOptions.put ("console", true);
        ltOptions.put ("devicelog", true);
        return ltOptions;
    }

    private DesiredCapabilities setCapabilities() {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("lt:options", ltOptions());
        return capabilities;
    }
    private void setDriver(final AndroidDriver driver) {
        AndroidDriverManager.DRIVER.set(driver);
    }

    private void setupBrowserTimeouts() {
        getAndroidDriver().manage()
                .timeouts()
                .implicitlyWait(Duration.ofSeconds(20));
    }
}

In AndroidDriverManager class, the first method that we will be discussing is the createAndroidDriver() that will set the Android Driver and its capabilities.

Need to convert Hex to RGB values? Use our Hex color to RGB Converter tool to convert Hex colors to RGB values — it’s fast, free, and accurate. Try it now for hassle-free conversions.

The ThreadLocal class is used to instantiate the Android Driver instance. This ensures that each thread has its isolated instance of the Android Driver. This will help us run the tests in parallel smoothly. Next, the setDriver() method will set the Android Driver.

For running the tests on the LambdaTest cloud grid, we need to provide the LambdaTest Username, Access Key, and Grid URL along with the desired capabilities. The LambdaTest Username and Access Key will be supplied while running the tests as the respective values are taken using the System.getProperty method.

The LambdaTest Username and Access Key can be fetched from the Account Settings >> Password & Security screen after logging in to the LambdaTest website.

The setCapabilities() method sets the desired capabilities for running the test on the LambdaTest cloud grid.

A separate ltOptions() method has been created to allow us to set all the LambdaTest capabilities for running the test on real Android devices. We need to provide the capabilities for automationName with the value “Flutter”. This particular capability setting needs to be provided for Flutter apps only.

These capabilities can easily be found on the LambdaTest Capabilities Generator, which generates the code while you set the desired capabilities from the UI.

You may notice that there are variables set for the following values in the ltOptions() method:

  • LT_USERNAME

  • LT_ACCESS_KEY

  • Platform

  • Platform Version

  • Device Name

  • Test Name

  • Build Name

  • App URL

All these values will be set using the testng.xml file hence the respective variables have been set here. This allows us to keep the platform and device details dynamic in the code and manage it using the testng.xml to run the test on different platform and device combinations.

@Builder annotation has been placed over the AndroidDriverManager class. It is an annotation from the Lombok library, and it will help set the platform, version, device, etc. details in builder pattern format.

Once the Android Driver and the desired capabilities are set. Next, we must find the mobile elements to interact with them and run the automation test.

Page Object Model (POM) is used in this project as it helps the code maintainability, readability, and reusability. Page Object Model implementation will create separate classes to maintain the Login and Catalog pages.

The LoginPage class will handle all the Page Objects of the Login page.

public class LoginPage {

    private final AppiumDriver driver;
    private final FlutterFinder finder;

    public LoginPage(final AppiumDriver driver) {
        this.driver = driver;
        this.finder = new FlutterFinder(driver);
    }

    private WebElement userNameField() {
        return this.finder.byValueKey("username");
    }

    private WebElement passwordField() {
        return this.finder.byValueKey("password");
    }

    private WebElement enterBtn() {
        return this.finder.byText("ENTER");
    }

    public CatalogPage performLogin(final String userName, final String password) {
        this.userNameField().sendKeys(userName);
        this.passwordField().sendKeys(password);
        this.enterBtn().click();
        return new CatalogPage(this.driver);

    }
}

The mobile elements for the Username and Password fields are returned by the userNameField() and passwordField() methods using the byValuKey() method of Appium Flutter Finder.

Need to decode an encoded URL? Our free online URL Decode tool can help to decode any encoded URL. Fast, simple, and reliable, Try it now.

Likewise, the mobile element for the ENTER button is returned by the enterBtn() method. The performLogin() method will help interact with the Username and Password fields by entering the respective values in the field and clicking the ENTER button to perform the login action.

An instance of the CatalogPage class is returned by the performLogin() method, as the app will move to the Catalog page after login.

The CatalogPage class will take care of all the Page Objects of the Catalog page.

public class CatalogPage {

    private final FlutterFinder finder;

    public CatalogPage(final AppiumDriver driver) {
        this.finder = new FlutterFinder(driver);
    }

    public String pageTitle() {
        return this.finder.byText("Catalog").getText();
    }

}

The title of the Catalog page will be located by the pageTitle() method using the byText() method of Appium Flutter Finder and will return its text in String format.

Setting up the Base Test

Now, verify the scenario discussed in the earlier section by writing the test. The first step is to create a BaseAndroidTest class that will initialize the Android Driver and set the respective desired capabilities to run the tests on real Android Device; finally, it will gracefully quit the driver after the tests are run.

public class BaseAndroidTest {

    protected AndroidDriverManager androidDriverManager;

    @Parameters({"buildName", "testName", "app", "platformName", "version", "device"})
    @BeforeClass(alwaysRun = true)
    public void setupTest(final String buildName, final String testName, @Optional("app") final String app, final Platform platform, final String platformVersion,
                          final String deviceName) {
            this.androidDriverManager = AndroidDriverManager.builder()
                    .buildName(buildName)
                    .testName(testName)
                    .app(app)
                    .platform(platform)
                    .platformVersion(platformVersion)
                    .deviceName(deviceName)
                    .build()
                    .createAndroidDriver();
    }

    @AfterClass(alwaysRun = true)
    public void tearDown() {
        this.androidDriverManager.quitDriver();
    }
}

The setupTest() method in the BaseAndroidTest class will run before any test is invoked. It will instantiate the AndroidDriverManager class and supply the build name, test name, application URL, platform name, platform version, and device name capabilities using the @Parameters annotation in TestNG from the testng.xml file and finally will create a new instance of the Android Driver using the createAndroidDriver() method.

Once all the tests are run, the tearDown() method will gracefully quit the driver.

Writing the Automation Test

Finally, in the last section of this blog on using Appium Flutter Driver with Java, we will write the test to verify the working of the Android Flutter application. As discussed in the earlier section of this blog, we need to verify the working of the Android Flutter application by performing login by entering Username and Password and clicking on the ENTER button.

Next, we must verify that the Catalog page is titled “Catalog.”

public class FlutterSampleAndroidAppTests extends BaseAndroidTest {


    @Test
    public void testProviderShopperApp() {
        final LoginPage loginPage = new LoginPage(this.androidDriverManager.getAndroidDriver());
        final CatalogPage catalogPage = loginPage.performLogin("faisal.k@user.com", "Pass1234");
        assertEquals(catalogPage.pageTitle(), "Catalog");
    }
}

FlutterSampleAndroidAppTests class that extends the BaseAndroidTests class, is created to write the Android automation tests. The BaseAndroidTests class is extended so we can inherit the instance of Android Driver from it.

The testProviderShopperApp() method performs all the actions to test the app. The LoginPage class is instantiated first and has the Android Driver instance passed as a Constructor parameter.

As the performLogin() method from the LoginPage class returns a new instance of the CatalogPage class, hence the following statement makes sense:

After the user logs in the app, the title of the Catalog page — “Catalog” is verified using the assertEquals() method of TestNG.

Test Execution using TestNG

The testng.xml file must be placed in the project’s root folder. The parameters test name, build name, platform name, platform version, device name, and App URL must be updated in the file.

This test will run on the LambdaTest cloud grid on Android 13Samsung Galaxy S21 5G real device.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Lambda tests Mobile automation test suite"  >
    <test name="Android Flutter app - Provider Shopper Tests " enabled="false">
        <parameter name="buildName" value="Android Flutter app Build"/>
        <parameter name="testName" value="Provider shopper android app tests"/>
        <parameter name="app" value="lt://APP10160161171700638856308564"/>
        <parameter name="platformName" value="ANDROID"/>
        <parameter name="version" value="13.0"/>
        <parameter name="device" value="Galaxy S21 5G"/>
        <classes>
            <class name="io.github.mfaisalkhatri.tests.FlutterSampleAndroidAppTests">
                <methods>
                    <include name="testProviderShopperApp"/>
                </methods>
            </class>
        </classes>
    </test> <!-- Test -->
</suite> <!-- Suite -->

We need to add the following values to run the tests on the LambdaTest cloud grid –

  • LambdaTest Username

  • LambdaTest Access Key

These values can be passed using the Run Configuration window in the IDE as
-DLT_USERNAME = -DLT_ACCESSKEY=

To run the test using IntelliJ, right-click on the testng.xml file and select the option Run ‘../testng.xml’.

Below is the screenshot of the test run using IntelliJ.

All the test execution can be viewed on the LambdaTest Dashboard, which provides all the minute details about the test execution.

LambdaTest Dashboard

Details like Video recordings, Screenshots, Appium logs, Device logs, OS name, OS version, Duration of test execution, etc., can be viewed in the build details screen by clicking the test session link on the dashboard page.

If you are a developer or tester looking to elevate your Appium automation skills, you can opt for the Appium 101 certification by LambdaTest! This comprehensive certification program allows you to use your Appium skills, covering essential concepts and best practices to automate real-world scenarios.

Convert your URLs into a secure and easy-to-read format with our URL Encode tool. Make sharing links easier and secured. Simply input your URL and let us do the rest.

Summary

There are multiple options of test automation frameworks that can be used to automate the Native applications. Nevertheless, Flutter applications present some limitations in this context. When it comes to identifying mobile elements in Native applications, the Appium Inspector tool proves useful, eliminating the necessity of delving into the source code of the applications. However, the Appium Inspector tool is ineffective for Flutter applications, requiring direct access to the source code. In this scenario, the Flutter Widget Inspector becomes crucial for locating the Flutter mobile elements.

Comparatively, automating the native application is much easier as we don’t need to know the programming language in which the native application is built. However, for Flutter, the tester needs to have some basic understanding of Dart programming language to configure and set up the Flutter app project for compiling and generating the Android and iOS builds.

The existing Appium Drivers, like UIAutomator, etc., don’t come in handy for the Flutter application. We need to have the Appium Flutter Driver to automate the Flutter application. Similarly, a separate Appium Flutter Finder library is required to locate the mobile elements, as the existing Appium libraries don’t work with Flutter.

I hope this blog helps you write automated tests for the Android Flutter application by saving time.

Happy Testing!