In the 2.0 of GameDriver, we introduced execution on Android as well as consoles. This allows you to build your game and run automated tests anywhere the Unity Engine is deployed, as long as the environment supports GameDriver which requires .NET 4.7.x and either native Windows binary execution or the mono runtime. This article will cover everything you need to know in order to test Unity projects built for Android, which can then be run on either emulators or physical devices.


If following these steps doesn’t get your where you need to be, please let us know by opening a support ticket or emailing the steps take and results to support@gamedriver.io 


For this example, we used the Tennis Mobile game by Codeer Studio. This game can be purchased on the Unity Asset Store here. The test script used can be downloaded at the bottom of this article, along with a sample zip file containing the NUnit console and `run_script.sh` example you can modify for your tests. Be sure to follow the README.txt contained within it which mirrors the instructions here.


  1. Read Unity’s documentation for working with Android here. You will also need to build your Android project with the GameDriver agent. For more information regarding the installation and use of GameDriver, please refer to the installation instructions here.


  1. For a great primer on setting up Appium for testing locally (macOS-focused), read this article.


  1. For testing using a real device cloud, read BitBar’s Appium Tips for using C# → here


  1. The following packages.config settings were used for our testing. Note that the Selenium and Appium packages are version-sensitive when working with BitBar, and should not be updated to the latest version.


<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Appium.WebDriver" version="1.3.0.1" targetFramework="net472" />
  <package id="Castle.Core" version="4.3.1" targetFramework="net472" />
  <package id="Newtonsoft.Json" version="12.0.1" targetFramework="net472" />
  <package id="NUnit" version="3.13.1" targetFramework="net472" />
  <package id="NUnit.Console" version="3.12.0" targetFramework="net472" />
  <package id="NUnit.ConsoleRunner" version="3.12.0" targetFramework="net472" />
  <package id="NUnit.Extension.NUnitProjectLoader" version="3.6.0" targetFramework="net472" />
  <package id="NUnit.Extension.NUnitV2Driver" version="3.8.0" targetFramework="net472" />
  <package id="NUnit.Extension.NUnitV2ResultWriter" version="3.6.0" targetFramework="net472" />
  <package id="NUnit.Extension.TeamCityEventListener" version="1.0.7" targetFramework="net472" />
  <package id="NUnit.Extension.VSProjectLoader" version="3.8.0" targetFramework="net472" />
  <package id="NUnit3TestAdapter" version="3.17.0" targetFramework="net472" />
  <package id="Selenium.Support" version="2.46.0" targetFramework="net472" />
  <package id="Selenium.WebDriver" version="2.46.0" targetFramework="net472" />
</packages>


  1. Run > nuget install Test123/packages.config -OutputDirectory packages after updating packages.config to ensure your packages are installed/updated as needed.


  1. Update the test to accept external parameters, to differentiate between test modes. This is required since GameDriver’s ApiClient class supports multiple modes, and needs to know whether to connect to the Unity editor or a standalone device. For example:

public string testMode = TestContext.Parameters.Get("Mode", "IDE");


This will accept a new parameter from the NUnit Console Runner, with the default value “IDE”. We can then override the parameter when running the test with the following format:

mono ./ext/nunit3-console.exe ./tests/$TEST


To then use this parameter during test execution, we insert the following in our [OneTimeSetup] section:

if (testMode == "IDE")
{
api.Connect("localhost", 19734, true, 30);
}
else api.Connect("localhost", 19734, false, 30);


It is certainly possible to simply pass the true/false parameter into the test directly, but this approach is easier to read and understand.


Note that for proper scoping, you will need to create the following outside of any test classes including your [OneTimeSetup]:

ApiClient api;
AppiumDriver<AndroidElement> driver;


  1. Read the steps for running server-side Appium tests with BitBar → here


  1. After running your tests against the Unity editor to verify they are functioning as expected, copy the <Test>/bin/Debug directory contents of your test into your Appium <Test>/tests folder.

  1. Copy the <Test>/packages/NUnit.ConsoleRunner.3.12.0/tools directory contents to your Appium <Test>/ext folder.


  1. Find the sample script for configuring Appium DesiredCapabilities → here


  1. For our testing, we used the following DesiredCapabilities:

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.SetCapability("device", "Android");
capabilities.SetCapability("deviceName", "Android");
capabilities.SetCapability("platformName", "Android");
capabilities.SetCapability("appPackage", "com.GameDriver.GDIOToolkit");
capabilities.SetCapability("appActivity", "com.unity3d.player.UnityPlayerActivity");
capabilities.SetCapability("newCommandTimeout", "600");
capabilities.SetCapability("testdroid_target", "Android");
capabilities.SetCapability("testdroid_project", "C# Appium");
capabilities.SetCapability("testdroid_testrun", "Android Run 1");


  1. Be sure to update appPackage as defined in the Unity Project Settings. Should be formatted as com.Company Name.Product Name, e.g.:

capabilities.SetCapability("appPackage","com.GameDriver.GDIOToolkit");

  1. Before saving your test package, we will also need to add the following lines to our [OneTimeSetup] section:

string arguments = "forward tcp:19734 tcp:19734";
var process = new Process();
var startInfo = new ProcessStartInfo

{
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Minimized,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
FileName = "adb",
Arguments = arguments
};

process.StartInfo = startInfo;


This allows us to forward communications intended for the GameDriver agent to the app running on the device, via the android debug bridge (ADB). The full test script used in this demonstration can be found at the bottom of this document.


  1. Create the run_tests.sh as outlined in the BitBar instructions above. For our testing, the following was used:

#!/bin/bash

unzip tests.zip # BitBar zips up the tests folder on upload, so this needs to be unzipped

## Test-specific variables
export APPIUM_APPFILE=$PWD/GameDriver_Demo.apk #Replace "GameDriver_Demo" with your Apk filename located in the current working directory
export TEST=${TEST:="GameDriver_BitBar_Tests.dll"} #Replace "GameDriver_BitBar_Tests" with the name of your NUnit Test Library name

## Desired capabilities:
export APPIUM_URL="http://localhost:4723/wd/hub" # Local & Cloud
export APPIUM_DEVICE="Local Device"
export APPIUM_PLATFORM="android"

## Mac Environment variables - comment out for Bitbar execution
#export ANDROID_HOME=/Users/$(whoami)/Library/Android/sdk
#export PATH=$PATH:$ANDROID_HOME/platform-tools
#export PATH=$PATH:$ANDROID_HOME/tools
#export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

echo "Starting Appium ..."
appium --log-timestamp &

ps -ef | grep appium

echo "RUN#1"
pwd

# use with --result attribute for BitBar execution, without for local Appium testing
#mono ./ext/nunit3-console.exe ./tests/$TEST --testparam:Mode=appium
mono ./ext/nunit3-console.exe ./tests/$TEST --testparam:Mode=appium --result="TEST-all.xml;transform=nunit3-junit.xslt"

echo "Testing script complete"


  1. For local Appium server troubleshooting, be sure to run the following command from the ANDROID_HOME directory. See example environment variable from the run_tests.sh file above for adb location.

adb forward tcp:19734 tcp:19734

  • To remove adb port forwarding, in case you need to get back to local Unity editor testing, run the command:

adb forward --remove tcp:19734

  • If you receive the following error, be sure to quit your Unity editor session as it may have an ADB connection running in the background.

OpenQA.Selenium.WebDriverException: An exception with a null response was thrown sending an HTTP request to the remote WebDriver server for URL http://localhost:4723/wd/hub/session. The status of the exception was ReceiveFailure, and the message was: Error getting response stream (ReadDoneAsync2): ReceiveFailure ---> System.Net.WebException: Error getting response stream (ReadDoneAsync2): ReceiveFailure

  1. Once you have configured your test to run using the local Appium environment, be sure to comment/uncomment the lines indicated in step 13 for execution in BitBar before zipping up your test script. Also, if you are using macOS be sure to zip the file contents and not the folder containing the files, or you're `run_tests.sh` will not be at the root of your unzipped folder and the tests will fail.


  1. Sign up for a trial at BitBar.com


  1. Once registered, go to Automation > Create Automated Test in your Mobile App Testing Dashboard


  1. Select the Target OS of “Android” and the Framework “Appium Android Server Side”


  1. Select the zip file you created from steps 7 and 15, and the .apk file you created from step 1. Leave the default selection for Choose Devices, at least for the trial.



  1. Start your tests. From here, you should be able to view the test running on the physical devices for a short period of time. Once the test is completed, you can view the results for each device, including the resource utilization and logs.



That's it. Time to celebrate! If you have any issues with this process, please let us know via support@gamedriver.io or by leaving a comment here.