In software engineering, graphical user interface testing is the process of testing a product's graphical user interface to ensure it meets its specifications. This is normally done through the use of a variety of test cases.
-- Wikipedia
UI Testing (also know as End-to-End Testing, or sometimes Integration Testing) helps with two aspects of software development:
- Regression Testing: to ensure that all possible user journeys - especially the edge cases, or for rarely visited screens - consistently funcion correctly across releases.
- New features development: to help determine 1. the minimum amount of work to be done to implement the feature, 2. that the new feature functions correctly, 3. helps ensuring the app is more accessible for people with disabilities. Moreover, done during development, UI Testing ensures immediate regression testing exposure.
Although UI Testing helps ensuring all systems - e.g. the database and the different microservices/modules that make up the app - are integrated correctly, it shouldn't be used to test external dependencies such as APIs, Analytical services, Logging, etc.
A test case is a specification of the inputs, execution conditions, testing procedure, and expected results that define a single test to be executed to achieve a particular software testing objective, such as to exercise a particular program path or to verify compliance with a specific requirement.
-- Wikipedia
A test case class is a collection of test cases. Each test case describes the routine to be tested and asserts that certain expectations are met. Each test case should be abstract and brief. The implementation details to set up the test or to perform actions should not belong to the test but to page objects.
A page object represents a single screen. It abstracts all elements on screen and all actions the user can perform on it. Read the full definition in this article by Martin Fowler.
- ALL API calls must be stubbed. The tests should be able to run without any internet connection.
- Always use existing tests as a guide for structure.
- All test case files should inherit from a wrapped version of your framework's base test case - e.g.
XCUITestCase
to take advantage of helper methods, instance variables, and to ensure a common set up. We'll call this wrapper theTestCase
class. - Launch arguments to control state and features in the app are passed to a common launch method provided by the
TestCase
class. - There is usually a one-to-one mapping between screens and Page Objects.
- Locators for elements in your tests should all be handled in the page objects. Locators that require input from the test (e.g. a restaurant name) should be created by a method in the page object rather than in the test case itself.
- Asserts live in the test cases, not the Page Objects. It makes test results much easier to interpret and it makes the tests much easier to read.
- Abstractions that are very specific to your test should live in the test case file.
- Abstractions that are very specific to your page object should live in the page object file.
- Page objects must never interact with other page objects. It’s better to either call each page object in turn in a test or to group the calls together in a helper method within the test file. While this means a few more lines of code in the tests, it decreases the complexity of the test suite by an order of magnitude.
- The
TestCase
class should set the locale (language and other internationalization parameters) of the app via launch arguments and by using default values as appropriate.
API are done using bundles of files used by one or more test cases. These bundles consist of however many JSON blobs you need, plus a file that contains the rules for when the each is JSON should be returned. These all live in a Stub Bundles folder.
To tell a test to use a specific bundle you generally pass a launch argument containing a list of bundles you want to use.
With this option, the TestCase
class should set up the tests so that all HTTP requests are intercepted by a proxy and redirected to the JSON blobs using the rules in each stubs bundle.
An alternative to Option 1 is to have an APIClient
class configurable with a base URL. When running the tests all clients will have a localhost
base URL. A script should start a local server before any test is run, configured with all routes used by the application. Each route is stubbed with an appropriate JSON response.