Automated Xamarin UI Tests using Azure DevOps and App Center

Testing is important part of the release management process. Having automated tests in your app is really great advantage for your app from many aspects. Having automated tests means your app can be tested on many devices and densities at once. Saves time, can be run on multiple platforms in the same time and does not require mandatory human presence at the time of testing. And these are just a small examples from the pool of benefits of having Automated UI Tests for apps.

The really great thing is that Azure DevOps together with the App Center are having this awesome opportunity. In this Post I will show you how to create a pipeline in Azure DevOps that will run your UITests in App Center.

Pre-requirements

Before creating the pipeline there are few things that have to be provided.

  • Application archive file. For Xamarin apps it can be an .ipa file(Xamarin.iOS) or .apk/.aab(Xamarin.Android). We are going to use these files to preform the tests on.
  • Xamarin.UITests (or any other Test platform you want to use that is supported on AppCenter) project where the app test are written. From this project we are going to create the test assemblies so we can preform the tests on the archive files.
  • App Center and Azure DevOps subscription. To run the tests on those services.

Setup

Navigate to your project in your organization on Azure DevOps and from pipeline choose New Pipeline, to create new pipeline. We are going to use the Classic Editor instead the YAML, so select Use the classic editor. Next thing is to select the set the source where our project is hosted and the default branch for manual and scheduled builds. Once that is done click on continue. From the templates search and choose Empty pipeline.

If you want to put the Creation of the archives files and Running the UITests phases in the same pipeline select Xamarin.iOS or Xamarin.Android templates. There you will find the tasks for App Center.

Once you find the Empty pipeline click on it and apply.

UI Tests Pipeline creation

First set up a representative name for your pipeline. Once that is done select Pipeline.

  • Add name for the pipeline in Name field.
  • Set the machine that will build and execute your tests. You can choose Hosted > Azure Pipelines and you will be given a capable machine that can do that for you. Of choose Private > The name of your pool, to choose capable agent from your private pool of agents. If you are going to use the pipeline for the iOS app choose Mac machine else for Android you can go with Windows or Mac Machine.

By clicking on Agent job in the Agent pool we can see that <inherit from pipeline> is selected by default. That means that for this phase we will use the set up from the pipeline done in the steps above.

Nuget tasks

First thing to do is to add the Nuget tasks used to restore the Nuget packages for our project. Click on the plus icon near Agent job and select NuGet tool installer and then add NuGet to restore the nugets.

  • In the NuGet tool installer you can select the version of the installer.
  • In the NuGet task click on the three dots icon and select the .sln file to restore the nugets for your solution

Download archive file

If we are having a pipeline that builds our app, where we can find .ipa file and/or .apk/.aab file we will have to select from the tasks Download build artifacts. If you are not sure how to create these pipelines you can check the following links:

For Xamarin.Android – .aab file – Android App Bundle for Xamarin.Android apps using Azure DevOps and App Center

For Xamarin.iOS – .ipa file – Build Xamarin iOS app with Azure DevOps

  • Select Specific build radio button and two extra fields will appear
  • In the Project choose the project that contains the archive.
  • And in Pipeline choose the pipeline that contains the archive
  • In the Build version to download choose the Latest or a specific build you want to use for the testing
  • For Default type choose Specific type radio button and in the Matching pattern type **/NameOfYourArcive.extensionOfYourArchive or if that is the only file with .ipa or .aab/.apk extension you can use this matching pattern **/*.ipa or **/*.aab or **/*.apk
  • Destination directory is where your file will be downloaded so we are fine with the Artifact directory which is preselected by default

Build UITests and create built test assemblies

From the tasks add MSBuild task. This task will be used to build the Xamarin.UITest(or any other type of project supported on App Center) project and create the build test assemblies. Once that is selected do the following setup.

  • In the Project click on the three dots and select the Xamarin.UITests project: YourProject.csproj file
  • For MSBuild version and MSBuild architecture set up the configuration of the MSBuild.
  • For Configuration set the configuration in which you expect the UITests to be used, Debug, Release (Alpha, Beta, Prod – as custom created environments) . In the variables create variable with name BuildConfiguration and value e.g. Release. In Configuration field put $(BuildConfiguration)
  • In the MSBuild Arguments set the path where you want your test assemblies to be placed. We will use this path in the next task. That can be done something like this /p:OutputPath=$(build.binariesdirectory)/uitests. Setting this way the they will be added in the binaries(b) > uitests folder

Create connection with App Center

Now since we have the archive file and the test assemblies we will need to provide them to the App Center to see out tests running there. For that from the tasks select App Center test and do the following setup.

  • In the Binary application file path set the path of your archive. Because in the steps above(section: Download archive file) we set the Artifacts directory the path will look something like this: $(System.ArtifactsDirectory)/drop/NameOfYourArcive.extensionOfYourArchive
  • In the Prepare tests section for Test Framework choose the framework your tests are written with e.g. Xamarin UI Tests.
  • In the Build directory choose Path to directory with built test assemblies, in the previous step we explained where are we going to put the build assemblies and for this pipeline the path will look like this $(build.binariesdirectory)/uitests
  • If you have Store password, Key alias or Key password set them in the Variables lock them and use them safely in your pipeline. For this one we will left that empty.
  • In the Test tools directory locate the path of the test-cloud.exe file. This file is located in your Packages > Xamarin.UITests nuget file (if you are using Xamarin UI Tests) > version of the nuget package > tools the path will look something like this /.nuget/packages/xamarin.uitest/3.0.7/tools

Next is to set the Run Tests section

  • In the Authentication method set we can choose App Center service connection or Credentials. The main difference between these two is Service Connection can be used in multiple pipelines if permitted and Credentials are just for this specific pipeline.
    • If you choose Service connection. Click on Manage and click on New service connection. Search for Visual Studio App Center and then Next. In the Api Token put the token generated under your project in App Center(appcenter.ms) > Account Settings (click on account top right) > Scroll to Api Token > Add new token. Copy the generated Api Token and paste it in this field. In Service connection name add representative name for your connection. Click Save and get back to the pipeline. Click on the Refresh button and the connection will appear.
    • If you choose credentials in the App Center username add your App Center username and for App Center password the password for your App Center account. It is important to create these as locked variables so anyone with the access of the pipeline can not see our credentials.
  • Set the App slug field. The App slug is combination of your username and the app identifier. Go to App Center(appcenter.ms) > Select your project. From the url copy {username}/apps/{yourProjectName} and remove /apps. The App slug should look something like this stefanijapopovska/UITestingDemo
  • In the Devices set the previously created Device set in the App Center(App Center > Test(from menu) > Device sets). This is something similar as the App slug. It should look something like this {username}/{nameOfYourDeviceSet} e.g. stefanijapopovska/UITestingDemoDeviceSet
  • In dSYM directory you can choose the path for iOS symbols

Save & Queue.

Android App Bundle for Xamarin.Android apps using Azure DevOps and App Center

Few days passed since the amazing event – Xamarin Experts Day and most of the questions I got were how to support the new presented upload format Android App Bundle – .aab using Azure DevOps and AppCenter since my topic was DevOps: Continuous delivery for Xamarin application, Azure DevOps and App Center, and in the demo I was using a Xamarin.Android build definition.

Note: The source code used for the build definition can be found on Github

And YES, more than expected, because many of us has seen this warning when creating a release on Play Store.

Further more, this awesome new publishing format will allow us to deliver smaller app, optimized for lots of devices and factors. If still not using it do not worry, Xamarin team already took care for all. You can read more in the Official site for Android developers or in the initial support for Xamarin.Android in Xamarin.Android 9.4 release notes and the Xamarin.Android 10.0 release notes

Android App Bundle with Azure DevOps

Prepare your app

Before looking into the processes, let’s take a look at the steps that need to be done, so your app will be prepared for deployment in this format.

Set AndroidPackageFormat property. It can be done by adding these lines of code in the .csproj file for the Android project.

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

    <AndroidPackageFormat>aab</AndroidPackageFormat>

</PropertyGroup>

Edit your build definition

With all this set up navigate to Azure DevOps and edit the Android build definition. The definition that builds the app should look something like this:

For now just disable the current Xamarin.Android task that builds the Android app with Xamarin. It is important not to delete it because soon this feature will be available directly in this task. But let’s take a look at the alternative for now. 

Search for MsBuild task, that builds with MSBuild. After adding it, in the Project field set your Android .csproj file and set the MsBuild options like they are on your Xamarin.Android task. 

Next thing to do is to add additional arguments for the build. Set these arguments in the MSBuild Arguments field:

-t:SignAndroidPackage 

-p:Configuration=Release 

-p:AndroidKeyStore=True

-p:AndroidSigningKeyStore=$(KeyStoreName)

-p:AndroidSigningStorePass=$(KeyStorePass) 

-p:AndroidSigningKeyAlias=$(KeyStoreAlias)

-p:AndroidSigningKeyPass=$(KeyPass)

When AndroidPackageFormat is set as shown above, the SignAndroidPackage will create the .aab file in the bin directory, respectively in the chosen build configuration folder – the Release folder.

In the AndroidSigningKeyStore set the path where you store your .keystore file, if downloading from Secure Files – Library, check the target path folder inserted in the Download Secure File task.

After setting all these your YAML should look something like this:

steps:

- task: MSBuild@1

  displayName: 'Build XamExpertsDay App'

  inputs:

    solution: XamExpertsDay.Android/XamExpertsDay.Android.csproj

    msbuildArchitecture: x64

    msbuildArguments: '-t:SignAndroidPackage -p:Configuration=Release -p:AndroidKeyStore=True -p:AndroidSigningKeyStore=$(KeyStoreName) -p:AndroidSigningStorePass=$(KeyStorePass) -p:AndroidSigningKeyAlias=$(KeyStoreAlias) -p:AndroidSigningKeyPass=$(KeyPass)'

Running this task will sign the app, so the Android Signing task will no longer be needed. Disable that task, or just simply remove it.

Few more additional steps

The MSBuild will create the .aab file in the bin folder within the Android Project folder. If the folder or file path you want to publish is Artifact staging directory or Binary directory and you want to continue using them in the artifact for publishing, add the Copy files task in between and move the .aab file there. For source folder set the path to .aab file and for target folder the publishing path.

After filling in this the YAML for Copy files task should look something like this:

steps:

- task: CopyFiles@2

  displayName: 'Copy .aab to Binaries directory'

  inputs:

    SourceFolder: '$(System.DefaultWorkingDirectory)/XamExpertsDay.Android/bin/$(BuildConfiguration)/com.xamexpertsday.devopsdemo-Signed.aab'

    TargetFolder: '$(build.binariesdirectory)/$(BuildConfiguration)'

With setting all these the build definition should look like this:

Next redeploy the app, and everything will be ready for publishing.

Once we have the .aab file the build artifacts we will probably need to deploy it on the Play Store. To see how to do that visit this link: Release Android App Bundle for Xamarin.Android apps using Azure DevOps

Android App Bundle with App Center

For App Center just use the simple switch, that can be found by editing the already existing Android Build Definition.

Save & Build. Done 🙂 

Xamarin.iOS application branding using Github and App Center

Github & App center opportunities by making the release processes easier

The combination of these two powerful services has made the deployment for mobile application easier than ever, from building to testing and releasing in just few steps. I was amazed how repetitive process can be simplified and automated without any trouble for the developers. That is why I found it challenging and decided to create this article. 

What are we going to do next?

For this article I choose to make modification on the application that was already on my repository for a while, you can look at this article for more details. The aim of the application is to represent just one place in Postcard format. Looking from that point of view there was no point to create so many repositories for the same application and a real time saver would be if the same application is able to be used for various places. I was thinking for a way to reuse the same code, but yet create many more different apps.

Why we need to brand an application?

At the first sight this may looks irrational but there are many use case scenarios where this is required, here are some of them:

  1. You want to sell same product for different companies, but all of them have different name, different logo and colors that are typical for the brand.
  2. You want to create multiple environments from the same application ALPHA, BETA, PRODUCTION they all are the same app but may work with another API.

Lets get started

Lets navigate to App Center, and choose Build section from the Menu. Choose to edit already existing build definition. In the built configuration there is a section called Build scripts. By using this section we can execute custom scripts in our application. As in the official documentation is stated three type of scripts are available: post-clone, pre-build and post-build. The post-clone script runs immediately after the repository was cloned but before we do anything else on our end. The pre-build script runs before the actual build starts. The post-build script runs after the build has finished and we have copied all the necessary artifacts to the output directory.

Where to create these scripts?

Create these scripts in the same folder where your .sln file is, or .cspoj file if Android. Note that there is already a collection of scripts that you may find useful.

The full code which I am modifying can be find on Github. It is an Xamarin.iOS application referring to the above script changes are in appcenter-pre-build.sh file.

Firstly lets take a look of the essential configuration information changes, that are under info.plist file.

  •  Change App Name – Changing application name identifies what name users will see (from Postcard Zagreb -> Postcard Bitola)
plutil -replace CFBundleName -string "$BUNDLE_NAME" $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Info.plist
  • Change the App bundle identifier – Changing the identifier means that we are creating unique application for any of the brands. (com.stretchyheader.ios.zagreb -> com.stretchyheader.ios.bitola) 
plutil -replace CFBundleIdentifier -string $BUNDLE_IDENTIFIER $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Info.plist
  • Change version name – Changing version name means that our branded app does not need to be the same version name(1.0, 2.0 …) as the original app
plutil -replace CFBundleShortVersionString -string $BUNDLE_VERSION $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Info.plist

Further more the changes should be applied as well as on the constants for the application. This usually includes Colors, Translations specific for application, Rules that tend to be modified during different scenario’s, variables that are used in the entire application.

Note: While developing application we have to be sure that we always use the same resource. e.g.: Using class for color palette, not hardcoding the colors. 

In this case Branding folder files are what is going to be modified.

  • Change color palette – Static content where Colors are placed
find $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/ColorPalette.cs -type f -exec sed -i '' "s/PrimaryColor\ =\ \(.*\)/PrimaryColor\ =\ UIColor.FromRGB($PRIMARY_COLOR_R,$PRIMARY_COLOR_G,$PRIMARY_COLOR_B);/g" {} \;
	
find $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/ColorPalette.cs -type f -exec sed -i '' "s/AccentColor\ =\ \(.*\)/AccentColor\ =\ UIColor.FromRGB($ACCENT_COLOR_R,$ACCENT_COLOR_G,$ACCENT_COLOR_B);/g" {} \;
  • Change content – Dynamic data can be really complex to modify, for that purpose I chose a powerful command plutil as helper
plutil -convert xml1 $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.json -o $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.plist
	

plutil -replace headerImage -string $POSTCARD_HEADER_IMAGE $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.plist
	

plutil -replace title -string $POSTCARD_NAME $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.plist
	

plutil -replace description -string "$POSTCARD_DESCRIPTION" $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.plist
	

plutil -convert json -o $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.json  $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.plist
	

rm $APPCENTER_SOURCE_DIRECTORY/StretchyHeader.iOS/Branding/AppResources.plist 

In many of the scripts you may noticed that the environment variables are marked with $. Same as in the code, we do not hard code the values because we want to use the scripts for many postcards. Here is where we define the variables.

After applying all this changes and rebuilding the app from App Center, here is the product we get. A brand new postcard 🙂