This is the second blog of our XCUITest 101 series. In our previous post on setting up XCUITest framework, we got up and running with a sample XCUITest with Xcode 10. Apple’s XCUITest framework gives us an ability to record the basic user journeys to get started with XCUITest, but the recorded tests are not scalable and reusable. We have to take efforts to make the XCUITest more readable, scalable, maintainable and reusable.
As per the approach mentioned in the previous post, we are able to add more UI tests but there will be a lot of duplication of code which could make our UI tests hard to maintain and fix. Writing automated tests is pretty easy but writing solid tests is harder as the size and complexity of the project grow incrementally.
There are various testing approaches and test patterns available to make the tests scalable. In this post, we will cover how to make XCUITest tests robust by abstracting the common Swift code in the base class.
Create A Base Class for XCUITest Tests
Most of the testing frameworks use the concept of the base class to abstract the common functionality of test classes. In short, the base class is the superclass which offers the common functionality to test classes. In our XCUITest101 Xcode project, we have a UI test class
XCUITest101UITests.swift with all the methods like the setup, teardown and test methods in a single class. If we want to add new XCUITest tests, then we have to repeat the setup and teardown methods per test class. Clearly, this will create a lot of duplicate code in our iOS project which makes it hard to maintain later on and might prolong your test execution on a mobile device cloud. In order to avoid this, let’s create a base UI Test class from Xcode –> File –> New –> File –> Swift File –> Next and name the file XCUITestBase and make sure we have selected the target XCUITest101UITest for this file.
This will create a new file
XCUITestBase.swift under the UI test target where we can abstract the common code.
Abstract the Common Testing Workflow
Now that, we have created the base class for XCUITest, we can think about the common and repetitive code that we can include in the base class for iOS device testing. Looking at our existing test class XCUITest101UITests, we can abstract following things in the base class:
- Setup and Teardown methods
- The instance of
XCUIApplication()that might be needed in the later tests
These two are the very obvious things that we must abstract so that it can be reused later. As the project and test suits grow, however, there might be the need to abstract the more common workflows in the future. While writing XCUITest tests, it’s essential to configure our app in the state where we can do the tests reliably. Apple has provided the mechanism of launch arguments and launch environments to be passed to each test class. It makes sense to configure an ability to add launch arguments from the base class. One good example would be, we want to start each test from the clean state using the launch argument
XCUIApplication().launchArguments = ["-StartFromCleanState", "YES"]
This is an example of the launch argument but you can pass any arguments or environments created by your iOS developers. We can configure that in the base class and we will also extend the base class to
XCTestCase class. In the end, our
XCUITestBase class looks like this:
Now that we have created our base class, the next task is to modify our test XCUITest101UITest to the subclass of the base class and use common methods from the superclass.
Refactor UI Tests to Use Base Class
In order to refactor our original XCUITest101UITest we can take a few actions as mentioned below
- We don’t need the recorded test. So first let’s get rid of the
testRecorded()test from our test class.
- Next, we can rename our test method
testRefactored()with something more sensible. As this is verifying the welcome message, let’s rename this test with
- We have to replace superclass of the test from
XCUITestBaseso that we can use all the common workflows from the base class.
- Replace the instances of
appfrom the base class.
Once we are done with the above steps, our test class will look like this:
Now that our test class looks much better and tidy. We cut down our source code of 30+ lines to just 8 lines by using the base class. If you run this test by using the CMD+U key, you will see that our test is still passing without any issue. You can see the test logs from the Debug Area of Xcode which is usually opened by CMD+SHIFT+C (⇧⌘C) key in Xcode 10. In the case of our tests, logs look like this when the test is running in the simulators.
In the end, you can see that test will assert the welcome message and pass.
Try It Your self
The source code of this tutorial is available on the Github XCUITest101 repository in the
baseclass branch here. You can download the source code and run the tests in the Xcode 10 by yourself. From the command line, you can get the source code
$ git clone https://github.com/Shashikant86/XCUITest101 $ cd XCUITest101 $ git checkout baseclass $ open XCUITest101.xcodeproj/
Once the project gets opened in the Xcode 10, then press CMD+U to run the XCUITest.
In this post, we have abstracted the common code of XCUITest in the base class to avoid the duplication. However, there is still so much improvement needed to make our tests scalable and truly reusable. We will apply the Swift’s best test pattern to our XCUITest in the next blog.