Showing posts with label UI Testing. Show all posts
Showing posts with label UI Testing. Show all posts

Friday, 15 February 2019

Network Stub for UI Testing (iOS)

This is a quick walkthrough of network stub libraries options for iOS app testing. All of them start a local server and allow to specify JSON response for the request path. 

Benefits of using network stubs:

  • keep the production code clean ( no response mock code )
  • mock server instance hold by each XCTestCase, so each test case decides to use mock response or access real api by itself.
  • the response can be dynamically updated during test case.

A brief comparison is as shown in the table below:





























I've picked Swifter and Embassy and had a close look. The difference is Embassy support to mock slow network which will help if you want to test if loading view shows up correctly and doesn't block the UI. Besides,  Embassy provides more advanced usages such as recording response with other tools. The integration and basic usage of them are very similar

After installation, the only change we have to make in production code is specify the local host and scheme for mock server:


    var scheme: String {
        guard ProcessInfo.processInfo.arguments.contains("MockResponse") == false else {
            return "http://"

        }



    var host: String {
        guard ProcessInfo.processInfo.arguments.contains("MockResponse") == false else {
            return "localhost:8080"
        }

And for those UITests require mock server, add the MockResponse to launchArguments in setUp()

    
override func setUp() {
        super.setUp()
        // TODO: add mock response before launch
        app.launchArguments = ["UITests""MockResponseUsingSwifter""MockResponse"]
        app.launch()

    }


Now the most important step is map your mock response data to http request path before launch. Please check the sample code and template in my Github repo:

SampleUsageCode at Github


Note: Try Carthage to install if compiling issues can not be solved via CocoaPod.

Monday, 14 January 2019

Parallel Testing

Enable Parallel Testing

Edit Scheme -> Test -> Info -> Options -> Select 'Execute in parallel on Simulator'


Then XCode would run tests on cloned simulators for different test cases.
You can also specify the devices you want by command line

xcodebuild 
-workspace ????.xcworkspace 
-scheme ???? -sdk iphonesimulator 
-destination 'platform=iOS Simulator,id=????’ 
-destination 'platform=iOS Simulator,name=iPhone 6,OS=8.1'
test &

Note:
1. By default, the above approach dose not  support test cases interdependent among simulators
2. It slows down performance testing. Keep performance tests in its own scheme and disable parallel.

Expecting same testing case running in different simulators and communicating with each other. This article is worth reading.
https://medium.com/@Maryamfekri/how-to-run-uitest-for-messaging-features-in-an-ios-application-777de0440b99

Monday, 17 December 2018

Find UI Element for UITests

This tutorial discusses ways to find UIElement for UI Testing.
Check demo code at Github:
https://github.com/Sylvia-YiyinShen/FindElementForUITests
Easiest way is using the XCode built-in recording functionality



Tap the red Record button, XCode will build and run the app. Every gesture/interaction such as dragging, tapping, scrolling... will be automatically captured into code. Tap the Record button again when you want to end this mode.

Note: sometimes you may find the Record button is disabled. Make sure that you cursor is within the scope of your testing function.



Find element by text

element.exists will work for static element, check async function utilities?.waitForElementToAppear in my demo for dynamically populated element



You will find .staticTexts[""] doesn't work for other element, such as UIButton, NavigationBar...
You have to specify the corresponding element type.



What if the text on label, button and title is dynamic?  Now let's look at another approach

Find UIElement by indentifier

1. Specify the Identifier under Accessibility section in Identity Inspector

Or by code


2.  Find it by identifier in UITests



Tricks to find identifier and check why it is can not be found be identifier - Right click XCode and open Accessibility Inspector



Select the right simulator and tap Start Inspection


Next focus or tap an element in simulator, Accessibility Inspector will tell you the type of the element and wether it has an identifier.


Monday, 3 December 2018

UI/Unit Test Async Code

Check example code at Github:
https://github.com/Sylvia-YiyinShen/TestAsyncCode

This tutorial covers:
  • Unit testing async code via build-in XCTestCase
  • Unit testing async code via Quick/Nimble
  • UI testing async code

ExampleViewModel prepared for this tutorial as below,  just mocking an API call and exposing list data.




Unit testing

Now let's look at a test which will not be able to pass:



Since fetchBookList is an async function, the last two assertions will fail.  Although we can test bookList inside the completion block of fetchBookList, it doesn't work for other public properties of viewModel.

We need the help of XCTestExpectation. A succeeding example is as below:



If you are familiar with Quick/Nimble, we need the keyword toEventually instead of XCTestExpectation




UITesting

A failing test example just checking the existence of a label which will only appear on completion of the async function.


A succeeding test via sleep() which is not the good practice. Since we would never know the minimum time to complete the async function and we always have to make it longer. If sleep() has been heavily used through thousands of tests, there will be considerable time wasted.


Solution: