Monkey

public class Monkey

A general-purpose class for implementing randomised UI tests. This class lets you schedule blocks to be run at random or fixed intervals, and provides helper functions to generate random coordinates.

It has several extensions that implement actual event generation, using different methods. For normal usage, you will want to look at for instance the XCTest private API based extension.

If all you want to do is geneate some events and you do not care about the finer details, you can just use a test case like the following:

func testMonkey() {
    let application = XCUIApplication()

    // Workaround for bug in Xcode 7.3. Snapshots are not properly updated
    // when you initially call app.frame, resulting in a zero-sized rect.
    // Doing a random query seems to update everything properly.
    // TODO: Remove this when the Xcode bug is fixed!
    _ = application.descendants(matching: .any).element(boundBy: 0).frame

    // Initialise the monkey tester with the current device
    // frame. Giving an explicit seed will make it generate
    // the same sequence of events on each run, and leaving it
    // out will generate a new sequence on each run.
    let monkey = Monkey(frame: application.frame)
    //let monkey = Monkey(seed: 123, frame: application.frame)

    // Add actions for the monkey to perform. We just use a
    // default set of actions for this, which is usually enough.
    // Use either one of these but maybe not both.
    // XCTest private actions seem to work better at the moment.
    // UIAutomation actions seem to work only on the simulator.
    monkey.addDefaultXCTestPrivateActions()
    //monkey.addDefaultUIAutomationActions()

    // Occasionally, use the regular XCTest functionality
    // to check if an alert is shown, and click a random
    // button on it.
    monkey.addXCTestTapAlertAction(interval: 100, application: application)

    // Run the monkey test indefinitely.
    monkey.monkeyAround()
}
  • Create a Monkey object with a randomised seed. This instance will generate a different stream of events each time it is created.

    There is an XCTest bug to be aware of when finding the frame to use. Here is an example of how to work around this problem:

    let application = XCUIApplication()
    
    // Workaround for bug in Xcode 7.3 and later. Snapshots are not properly
    // updated when you initially call app.frame, resulting in a zero-sized rect.
    // Doing a random query seems to update everything properly.
    _ = application.descendants(matching: .any).element(boundBy: 0).frame
    
    let monkey = Monkey(frame: application.frame)
    

    Declaration

    Swift

    public convenience init(frame: CGRect)

    Parameters

    frame

    The frame to generate events in. Should be set to the size of the device being tested.

  • Create a Monkey object with a fixed seed. This instance will generate the exact same stream of events each time it is created. Create a Monkey object with a randomised seed. This instance will generate a different stream of events each time it is created.

    There is an XCTest bug to be aware of when finding the frame to use. Here is an example of how to work around this problem:

    let application = XCUIApplication()
    
    // Workaround for bug in Xcode 7.3 and later. Snapshots are not properly
    // updated when you initially call app.frame, resulting in a zero-sized rect.
    // Doing a random query seems to update everything properly.
    _ = application.descendants(matching: .any).element(boundBy: 0).frame
    
    let monkey = Monkey(seed: 0, frame: application.frame)
    

    Declaration

    Swift

    public init(seed: UInt32, frame: CGRect)

    Parameters

    seed

    The random seed to use. Each value will generate a different stream of events.

    frame

    The frame to generate events in. Should be set to the size of the device being tested.

  • Generate a number of random events.

    Declaration

    Swift

    public func monkeyAround(iterations: Int)

    Parameters

    iterations

    The number of random events to generate. Does not include any fixed interval events that may also be generated.

  • Generate random events or fixed-interval events based forever, for a specific duration or until the app crashes.

    Declaration

    Swift

    public func monkeyAround(forDuration duration: TimeInterval = .infinity)

    Parameters

    duration

    The duration for which to generate the random events. Set to .infinity by default.

  • Generate one random event.

    Declaration

    Swift

    public func actRandomly()
  • Generate any pending fixed-interval events.

    Declaration

    Swift

    public func actRegularly()
  • Add a block for generating randomised events.

    Declaration

    Swift

    public func addAction(weight: Double, action: @escaping (Void) -> Void)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

    action

    The block to run when this event is generated.

  • Add a block for fixed-interval events.

    Declaration

    Swift

    public func addAction(interval: Int, action: @escaping (Void) -> Void)

    Parameters

    interval

    How often to generate this event. One of these events will be generated after this many randomised events have been generated.

    action

    The block to run when this event is generated.

  • Generate a random Int.

    Declaration

    Swift

    public func randomInt(lessThan: Int) -> Int

    Parameters

    lessThan

    The returned value will be less than this value, and greater than or equal to zero.

  • Generate a random UInt.

    Declaration

    Swift

    public func randomUInt(lessThan: UInt) -> UInt

    Parameters

    lessThan

    The returned value will be less than this value, and greater than or equal to zero.

  • Generate a random CGFloat.

    Declaration

    Swift

    public func randomCGFloat(lessThan: CGFloat = 1) -> CGFloat

    Parameters

    lessThan

    The returned value will be less than this value, and greater than or equal to zero.

  • Generate a random CGPoint inside the frame of the app.

    Declaration

    Swift

    public func randomPoint() -> CGPoint
  • Generate a random CGPoint inside the frame of the app, avoiding the areas at the top and bottom of the screen that trigger a panel pull-out.

    Declaration

    Swift

    public func randomPointAvoidingPanelAreas() -> CGPoint
  • Generate a random CGPoint inside the given CGRect.

    Declaration

    Swift

    public func randomPoint(inRect rect: CGRect) -> CGPoint

    Parameters

    inRect

    The rect within which to pick the point.

  • Generate a random CGRect inside the frame of the app.

    Declaration

    Swift

    public func randomRect() -> CGRect
  • Generate a random CGRect inside the frame of the app, sized to a given fraction of the whole frame.

    Declaration

    Swift

    public func randomRect(sizeFraction: CGFloat) -> CGRect

    Parameters

    sizeFraction

    The fraction of the size of the frame to use as the of the area for generated points.

  • Generate an array of random CGPoints in a loose cluster.

    Declaration

    Swift

    public func randomClusteredPoints(count: Int) -> [CGPoint]
  • Add a sane default set of event generation actions using the private UIAutomation API. Use this function if you just want to generate some events, and do not have strong requirements on exactly which ones you need.

    Declaration

    Swift

    public func addDefaultUIAutomationActions()
  • Add an action that generates a single tap event using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationSingleTapAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a tap, with a possibility for multiple taps with multiple fingers, or long taps, using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationTapAction(weight: Double, multipleTapProbability: Double = 0.05,
        multipleTouchProbability: Double = 0.05, longPressProbability: Double = 0.05)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

    multipleTapProbability

    Probability that the tap event will tap multiple times. Between 0 and 1.

    multipleTouchProbability

    Probability that the tap event will use multiple fingers. Between 0 and 1.

    longPressProbability

    Probability that the tap event will be a long press. Between 0 and 1.

  • Add an action that generates a drag event from one random screen position to another using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationDragAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a flick event from one random screen position to another using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationFlickAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a pinch close gesture at a random screen position using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationPinchCloseAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a pinch open gesture at a random screen position using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationPinchOpenAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a rotation gesture at a random screen position over a random angle using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationRotateAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a device rotation event using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationOrientationAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a volume up click event using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationClickVolumeUpAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a volume down click event using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationClickVolumeDownAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a shake event using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationShakeAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a lock button click event and subsequent unlock drag event using the private UIAutomation API.

    Declaration

    Swift

    public func addUIAutomationLockAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that checks, at a fixed interval, if an alert is being displayed, and if so, selects a random button on it.

    Declaration

    Swift

    public func addXCTestTapAlertAction(interval: Int, application: XCUIApplication)

    Parameters

    interval

    How often to generate this event. One of these events will be generated after this many randomised events have been generated.

    application

    The XCUIApplication object for the current application.

  • Add a sane default set of event generation actions using the private XCTest API. Use this function if you just want to generate some events, and do not have strong requirements on exactly which ones you need.

    Declaration

    Swift

    public func addDefaultXCTestPrivateActions()
  • Add an action that generates a tap, with a possibility for multiple taps with multiple fingers, using the private XCTest API.

    Declaration

    Swift

    public func addXCTestTapAction(weight: Double, multipleTapProbability: Double = 0.05,
        multipleTouchProbability: Double = 0.05)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

    multipleTapProbability

    Probability that the tap event will tap multiple times. Between 0 and 1.

    multipleTouchProbability

    Probability that the tap event will use multiple fingers. Between 0 and 1.

  • Add an action that generates a long press event using the private XCTest API.

    Declaration

    Swift

    public func addXCTestLongPressAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a drag event from one random screen position to another using the private XCTest API.

    Declaration

    Swift

    public func addXCTestDragAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a pinch close gesture at a random screen position using the private XCTest API.

    Declaration

    Swift

    public func addXCTestPinchCloseAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a pinch open gesture at a random screen position using the private XCTest API.

    Declaration

    Swift

    public func addXCTestPinchOpenAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a rotation gesture at a random screen position over a random angle using the private XCTest API.

    Declaration

    Swift

    public func addXCTestRotateAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.

  • Add an action that generates a device rotation event using the private XCTest API. Does not currently work!

    Declaration

    Swift

    public func addXCTestOrientationAction(weight: Double)

    Parameters

    weight

    The relative probability of this event being generated. Can be any value larger than zero. Probabilities will be normalised to the sum of all relative probabilities.