As mentioned previously, in this section, we will learn about some of the commonly used methods that we can use with the UITest framework. The UITest framework provides you with a way of automating the interactions between your iOS, or Android apps using C# and the NUnit testing platform.
We will be using an instance of the IApp
and ConfigureApp
classes that will be used to create our iOS and Android IApp
instances to handle all the interactions within the UI.
As we progress throughout the next couple of sections, we will be taking a closer look at how to create IApp
instances using the ConfigureApp
class. The UITest framework provides you with several APIs that you can use to interact with an app's user interface.
The following table describes some of the more commonly used methods and the ones that we will be using to test the TrackMyWalks
app:
UITest methods |
Description |
|
This will essentially take a screenshot of the current state of the app. |
|
This is used to send a tap interaction to a specific element on the app's current screen. |
|
These methods are used to add and remove text from input elements such as the entry views used within |
|
This method is essentially used to locate or find elements that are currently displayed within the app's screen. |
|
This command is commonly used to interact in real-time with the app through the terminal using the UITest API. |
|
This method is used to pause the test until a specific element appears on the app's current screen within a specific timeout period. |
Methods such as the Query
and WaitForElement
return an AppResult[]
object that you can essentially use to determine the results of the call. An example would be that if you used the Query
method call that returns an empty result set, we can be sure that the element does not exist within the app's current screen.
As you will see from the methods displayed in the following table, these are essentially all the members pertaining to the AppQuery
class that are used by the Query
and WaitForElement
method members of the IApp
methods:
AppQuery class methods |
Description |
|
Finds elements on the app's current screen, based on their class type. |
|
Finds elements within the app's current screen, based on their text or identifier. |
|
Performs CSS selector operations on the contents of a WebView on the app's current screen. |
If you are interested in learning more about the various types of UITest methods, please refer to the Introduction to Xamarin.UITest at https://developer.xamarin.com/guides/testcloud/uitest/intro-to-uitest/ .
Now that you understand some of the most commonly used UITest methods, we can start to implement some tests which we will be covering over the next couple of sections within this chapter.
Prior to starting an app and interacting with it using the UITest framework, we need to do some preliminary initialization steps for which we'll make some modifications within the AppInitializer
class. The AppInitializer
class contains a static method called StartApp
.
This static method is called each time the test's Setup
method is called to get an IApp
instance. It currently supports both the iOSApp
and AndroidApp
as defined by the ConfigureApp
class.
One thing that you will notice within the AppInitializer
class is that the ApkFile
and the AppBundle
have both been commented out. You will need to uncomment these if you would like to run the tests locally within the unit test pane using Xamarin Studio.
using System; using System.IO; using System.Linq; using Xamarin.UITest; using Xamarin.UITest.Queries; namespace TrackMyWalks.UITests { public class AppInitializer { public static IApp StartApp(Platform platform) { ... ... ... if (platform == Platform.Android) { return ConfigureApp.Android // TODO: Update this path to point to your Android // app and uncomment the code if the app is not // included in the solution. //.ApkFile("../../../Droid/bin/Debug /TrackMyWalks.apk").StartApp(); } return ConfigureApp.iOS // TODO: Update this path to point to your iOS app and // uncomment the code if the app is not included in the // solution. //.AppBundle("../../../iOS/bin/ iPhoneSimulator/Debug/TrackM // yWalks.iOS.app").StartApp(); } } }
As you can see from the preceding code snippet, the AppInitializer
class contains several different methods that are part of the ConfigureApp
method. The following table provides a brief description of what each one is used for:
ConfigureApp methods |
Description |
|
This method is used for specifying the path to the app bundle to use during testing. |
|
This method essentially launches the app within the simulator. |
|
This method is essentially used to enable debugging and logging of messages and is particularly useful if you need to troubleshoot problems when running the application using the simulator. |
|
This method configures the device to use with the device identifier. This can be used to detect iOS simulators using the following command line statement: xcrun instruments -s devices
|
|
This method is used to enable screenshots when you're running tests locally. By default, screenshots are always enabled whenever tests are being run using Xamarin Test Cloud. |
|
This method will essentially pause the test execution and invoke the REPL in a terminal prompt. |
As you can see, the AppInitializer
file doesn't contain much information, but as we work our way through this chapter, we will be adding the Xamarin.TestCloud.Agent
to the iOS portion of the TrackMyWalks
app so that we will be able to run our UITests.
In the previous section, we looked at some of the different types of methods that we can use to customize the AppInitializer
class so that we can specify different app bundles to use during testing, as well as to enable screenshots, and provide the ability to debug our unit tests within the Xamarin Studio environment.
In this section, we will begin by implementing a UITest that we can use to handle signing into Facebook and creating a new walk entry using the UITest framework.
Let's now start to implement the code required for our class by performing the following steps:
Test.cs
file which can be located within the TrackMyWalks.UITests
project as part of the TrackMyWalks.Tests
solution folder.Test.cs
file is displayed within the code editor, and enter in the following highlighted code sections, as shown in the code snippet:using System; using System.IO; using System.Linq; using NUnit.Framework; using Xamarin.UITest; using Xamarin.UITest.Queries; namespace TrackMyWalks.UITests { [TestFixture(Platform.Android)] [TestFixture(Platform.iOS)] public class Tests { IApp app; Platform platform;
Tests
instance method that will be responsible for creating a new instance of our IApp
instance. We update our entryCellPlatformClassName
string variable to return the type of TextField
, dependent on the platform that we are testing on. Under iOS, we use the UITextField
, whereas under Android it will use the default EntryCellEditText
class. Proceed and enter in the highlighted code sections within the following code snippet:string entryCellPlatformClassName; public Tests(Platform platform) { this.platform = platform; entryCellPlatformClassName = platform == Platform.iOS ? "UITextField" : "EntryCellEditText"; } [SetUp] public void BeforeEachTest() { app = AppInitializer.StartApp(platform); } [Test] public void AppLaunches() { app.Screenshot("First screen."); }
SignInToFacebook
instance method that will be responsible for handling the test's steps specifically to the Facebook sign-in process. This uses the user's login credentials to automate the login process prior to carrying out other steps within the UI. Proceed and enter in the highlighted code sections within the following code snippet:// Perform signing in to Facebook public void SignInToFacebook() { // Set up our Facebook credentials var FaceBookEmail = "<Your-Facebook-Email-Address> "; var FaceBookPassword = "<Your-Facebook-Password>"; // Wait for Login button within Facebook oAuth webview // to appear. app.WaitForElement(x => x.WebView().Css("[name=login]")); // Enter text within the webview with name="email" app.EnterText(x => x.WebView().Css("[name=email]"), FaceBookEmail); // Enter text within the webview with name="email" app.EnterText(x => x.WebView().Css("[name=pass]"), FaceBookPassword); app.ScrollDownTo(x => x.WebView().Css("[name=login]")); // Tap the button in the webview with name="login" app.Tap(x => x.WebView().Css("[name=login]")); }
PopulateEntryCellFields
instance method that will be responsible for handling the test steps specifically for the creation of a new walk entry. In this method, we make use of both the ClearText
and EnterText
methods of the UITest framework that will locate each entry field within the New Walk Entry form and populate it with the necessary information. The DismissKeyboard
method will, as the name suggests, dismiss the keyboard from the view and continue to the next step. Proceed and enter in the highlighted code sections within the following code snippet:// Populate our EntryCell Fields void PopulateEntryCellFields() { // Clear the default text entry for our Title EntryCell app.ClearText(x => x.Class (entryCellPlatformClassName).Index(0)); app.DismissKeyboard(); // Enter in some default text for our Title EntryCell app.EnterText(x => x.Class (entryCellPlatformClassName).Index(0), "This is a new walk Entry"); app.DismissKeyboard(); // Enter in some default text for our Notes EntryCell app.EnterText(x => x.Class(entryCellPlatformClassName).Index(1), "New Note Entry For Walk Entry"); app.DismissKeyboard(); // Clear the default text for our Image Url EntryCell app.ClearText(x => x.Class(entryCellPlatformClassName).Index(6)); app.DismissKeyboard(); // Enter in some default text Image Url EntryCell app.EnterText(x => x.Class(entryCellPlatformClassName).Index(6)," https://heuft.com/upload/image/ 400x267/no_image_placeholder.png"); app.DismissKeyboard(); }
ChooseDifficultyPicker
instance method that will be responsible for displaying the difficulty picker that contains various choices of difficulty for the user to choose from. All we are doing here is displaying the picker when the user taps into the cell entry, and dismissing the picker from the view when then user taps the Done
or OK
buttons. Proceed and enter the highlighted code sections, as shown within the following code snippet:// Automatically tap into the Difficulty Cell to display the // Difficulty Picker, and dismiss it by pressing the Done or // OK button. public void ChooseDifficultyPicker() { // Tap into Difficulty EntryCell app.Tap(x => x.Class(entryCellPlatformClassName).Index(5)); // Tap Done located within the Difficulty Picker Cell if (platform == Platform.iOS) app.Tap(x => x.Marked("Done")); else app.Tap(x => x.Marked("OK")); } }
CreateNewWalkEntry
UITest method that includes the [Test]
attribute. This is an abstract class that represents a test within the UITest and NUnit.Test
framework. This method will essentially be the main test driver and will call each of the other instance methods that we've previously declared. Within this method, we call our SignInToFacebook
method to perform the sign-in to Facebook, using the user's Facebook credentials.WaitForElement
method to wait until the main Track My Walks
screen has been displayed, prior to using the Assert.IsTrue
method to check to see if the Track My Walks
screen is displayed. If it's not displayed, our test will fail and display the assigned error message within the Test Results screen. Proceed and enter the following code sections shown within the following code snippet:[Test] public void CreateNewWalkEntry() { // Sign in to Facebook SignInToFacebook(); // Wait for main screen to appear and check for our // navigation title. var navigationBarTitle = (platform == Platform.iOS ? "Track My Walks - iOS" : "Track My Walks - Android"); var mainScreen = app.WaitForElement(x => x.Marked (navigationBarTitle).Class("UINavigationBar")); // Check to see if the Track My Walks - iOS main screen is // displayed. Assert.IsTrue(mainScreen.Any(), navigationBarTitle + " screen wasn't shown after signing in.");
Tap
method of the app
class instance and the Marked
method to find the Add
element within the app's current screen, and wait until the New Walk Entry
page is displayed within the screen. We then proceed to use the Assert.IsTrue
method to check to see if the New Walk Entry
screen has been successfully displayed. Alternatively, our test will fail and display the assigned error message within the Test Results screen. Proceed and enter in the highlighted code sections shown within the following code snippet:// Click on the Add button from our main screen and wait for // the New Walk Entry screen to appear. app.Tap(x => x.Marked("Add")); var newWalkEntryBarTitle = "New Walk Entry"; var newWalkEntryScreen = app.WaitForElement(x => x.Marked(newWalk EntryBarTitle)); // Check to ensure that our New Walk Entry screen was displayed. Assert.IsTrue(newWalkEntryScreen.Any(), newWalkEntryBarTitle + " screen was not shown after tapping the Add button.");
PopulateEntryCellFields
and ChooseDifficultyPicker
instance methods to populate our entry cell fields and handle the display of the difficulty picker selector. In our final steps, we use the Tap
method of the app
class instance, and we use the Marked
method to find the Save
element within the app's current screen. We'll wait until the Track My Walks
page is displayed, before using the Assert.IsTrue
method to check to see if the Track My Walks
screen has been successfully displayed. Alternatively, our test will fail and display the assigned error message within the Test Results screen. Proceed and enter the following highlighted code sections, as shown within the following code snippet:// Populate our Entry Cell Fields PopulateEntryCellFields(); // Display our Difficulty Picker selector. ChooseDifficultyPicker(); // Then tap on the Save button to save the details and exit // the screen. app.Tap(x => x.Marked("Save")); // Next, wait for main screen to appear mainScreen = app.WaitForElement(x => x.Marked (navigationBarTitle). Class("UINavigationBar")); // Check to see if the Track My Walks - iOS main screen is // displayed. Assert.IsTrue(mainScreen.Any(), navigationBarTitle + " screen wasn't shown after signing in."); } } }
In the preceding code snippet, we began by implementing the various instance methods that will be required to perform each test for our CreateNewWalkEntry
. We added the [Test]
attribute to our CreateNewWalkEntry
instance method. This method will essentially be the main test driver and call each of the other instance methods that we've previously declared. Within this method, we call our SignInToFacebook
method to perform the sign-in to Facebook, using the user's Facebook credentials. Upon successful login, we use the WaitForElement
method to wait until the main Track My Walks
screen has been displayed.
In the next step, we used the Tap
method of the App
class instance, and use the Marked
method to find the Add
element within the App's current screen, and wait until the New Walk Entry page is displayed within the screen. We then proceed to use the Assert.IsTrue
method to check to see if the New Walk Entry screen was successfully displayed. Alternatively, our test will fail and display the assigned error message within the Test Results screen.
18.226.88.110