Appfigurate™️
HomeDocumentation
  • Introducing Appfigurate™️ 3
  • Getting Started
    • Getting Started
    • Examples
    • Upgrade guide
      • v1.4.0 to v2.2.0
      • v2.1.1 to v2.2.0
      • v2.2.1 to v3.0.0
      • v3.2.1 to v4.0.0
    • iOS native app integration
      • iOS app extension integration
    • watchOS app integration
      • watchOS app extension integration
    • Android native app integration
    • Mobile Flutter integration
      • Flutter iOS
      • Flutter Android
    • React Native integration
      • iOS native module integration
      • Android native module integration
      • JavaScript integration
    • Third party remote configuration providers
      • Firebase Remote Config
      • Launch Darkly
      • Other third party remote configuration providers
  • Configuration subclasses
    • Supported property types
      • Boolean
      • Integer
      • Float
      • Double
      • Plain String
      • Encrypted String
    • Custom executable actions
    • Slider icon types
  • Additional reading
    • Info.plist options
    • AndroidManifest.xml options
    • Displaying overridden configuration
    • Security
      • Best practice
      • Encryption
      • Export compliance
      • App Store compliance
      • PrivacyInfo.xcprivacy
      • Rotating your private key
  • Automation testing
    • iOS native app automation testing
    • Android native automation testing
  • API
    • iOS and watchOS API
    • Android API
    • Mobile Flutter API
    • React Native API
  • Appfigurate User Guide
    • Introduction
    • Main menu
    • Select app
    • Add app
    • Import app
    • Install example apps
    • Settings
      • Passcode Lock
      • Restore
      • Backup
      • Delete all apps and Settings
      • Analytics
    • Edit app
    • Configure app
    • Permissions
  • Appfigurate SE user guide
    • Introduction
    • Manual encryption
      • ENCRYPTED_STRING macro/function
      • ENCRYPTED_STRING_IOS_WATCHOS macro/function
    • Setup iOS Simulator app
    • Setup Android Emulator app
    • Xcode source editor extension
      • Troubleshooting
    • Real device cloud testing services
      • BrowserStack
  • LEGAL
    • License Agreement
    • Privacy Policy
    • Release History
    • Third party notices
Powered by GitBook
On this page
  • Examples
  • Testing your app
  • Add APLConfiguration subclass to UI testing bundle
  • Ensure allowInvalidSignatures returns YES/true
  • Add an UIInterruptionMonitor
  • Create instance of APLConfiguration subclass
  • Apply configuration to XCUIApplication
  • Additional automation launch methods
  • Applying configuration at runtime to the app under test
  • Invoking functionality in the app under test at runtime
  • Instrument the app under test
  • Invoke functionality from your XCTestCase
  1. Automation testing

iOS native app automation testing

PreviousRotating your private keyNextAndroid native automation testing

Last updated 5 months ago

Appfigurate doesn't currently support automation testing watchOS, Mobile Flutter apps or React Native apps.

Appfigurate can change the configuration of an iOS app being automation tested using XCTestCase.

Examples

An example UI testing bundle AppfigurateExampleUITests is available in both and GitHub repositories. To test, ensure AppfigurateExample (ObjC/Swift iOS) is selected as the scheme, then long tap the run button to show more options and tap Test (⌘U).

Testing your app

Add APLConfiguration subclass to UI testing bundle

Tap on your subclass in the project navigator. In File inspector ‣ Target membership, tick on your UI testing bundle.

Ensure allowInvalidSignatures returns YES/true

In your subclass, confirm that your method returns YES/true when running automation tests. (Test schemes are by default run with a DEBUG build).

@objcMembers class ExampleConfiguration: APLConfiguration {
...
  override func allowInvalidSignatures() -> Bool {
    return !ENCRYPTED()
  }
...
@implementation ExampleConfiguration
...
- (BOOL) allowInvalidSignatures {
#if DEBUG
    return YES;
#else
    return NO;
#endif
}
...

Add an UIInterruptionMonitor

When the configuration is applied to the application on launch, the standard Appfigurate 'Configuration applied' alert is displayed. It is recommended you add an UIInterruptionMonitor to your XCTestCase to automatically dismiss this alert. A good place to do this in the setUp method.

addUIInterruptionMonitor(withDescription: "Appfigurate") { (element) -> Bool in
  if (element.elementType == .alert) {
    if (element.buttons["OK"].exists) {
      element.buttons["OK"].tap()
      return true
    } else if (element.buttons["Ignore"].exists) {
      element.buttons["Ignore"].tap()
      return true
    }
  }
  return false
}
[self addUIInterruptionMonitorWithDescription: @"Appfigurate" handler: ^(XCUIElement *element) {
    if (element.elementType == XCUIElementTypeAlert) {
        if ([element.buttons[@"OK"] exists]) {
            [element.buttons[@"OK"] tap];
            return YES;
        } else if ([element.buttons[@"Ignore"] exists]) {
            [element.buttons[@"Ignore"] tap];
            return YES;
        }
    }
    return NO;
}];

Create instance of APLConfiguration subclass

  • Set the properties required to be applied to your app to allow it to be tested correctly.

let c = APLConfiguration.shared() as! ExampleConfiguration
c.boolean = false
c.string_Textfield = "thursday"
ExampleConfiguration* c = (ExampleConfiguration*) [APLConfiguration sharedConfiguration];
c.boolean = NO;
c.string_Textfield = @"thursday";

Apply configuration to XCUIApplication

  • Launch your app.

let app = XCUIApplication()
app.launchArguments = c.automationLaunchArguments()
app.launch()
XCUIApplication* app = [XCUIApplication new];
app.launchArguments = [c automationLaunchArguments];
[app launch];

Additional automation launch methods

Applying configuration at runtime to the app under test

func testSendConfig() {
  app.launchArguments = c.automationLaunchArgumentsReset()
  app.launch()
  c.boolean = true
  c.automationSendConfiguration()
  ...
- (void)testSendConfig {
    app.launchArguments = [c automationLaunchArgumentsReset];
    [app launch];
    c.boolean = YES;
    [c automationSendConfiguration];
    ...

Invoking functionality in the app under test at runtime

Appfigurate allows you to invoke functionality in the app under test, at runtime, from your XCTestCase. Example use cases:

  • Setting mocked HTTP responses for HTTP requests in the app.

  • Share mocked objects between the XCTestCase and app.

  • Read and set the internal state of the app.

Instrument the app under test

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  APLApplicationDidFinishLaunchingWithOptions(launchOptions)
        
#if DEBUG
  APLAutomationMessageReceivedBlock { message, plist in
    let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first!
            
    if (message == "SetDarkMode") {
      let bool = plist as! Bool
      window.overrideUserInterfaceStyle = bool ? .dark : .light
    } else if message == "GetDarkMode" {
      let bool = window.traitCollection.userInterfaceStyle == .dark
      return bool
    }
    return nil
  }
#endif

  return true
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    APLApplicationDidFinishLaunchingWithOptions(launchOptions);
    
#if DEBUG
    APLAutomationMessageReceivedBlock(^id _Nullable(NSString * _Nonnull message, id  _Nullable plist) {
        UIWindow* window;
        for (window in [UIApplication sharedApplication].windows) {
            if ([window isKeyWindow]) {
                break;
            }
        }
            
        if ([message isEqualToString: @"SetDarkMode"]) {
            window.overrideUserInterfaceStyle = [plist boolValue] ? UIUserInterfaceStyleDark : UIUserInterfaceStyleLight;
        } else if ([message isEqualToString: @"GetDarkMode"]) {
            return [NSNumber numberWithBool: window.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark];
        }
        return nil;
    });
#endif
    return YES;
}

Invoke functionality from your XCTestCase

func testSendMessageToApplicationUnderTest() {
  app.launchArguments = c.automationLaunchArgumentsReset()
  app.launch()
  APLAutomationSendMessage("SetDarkMode", true, 3.0)
  XCTAssertTrue(APLAutomationSendMessage("GetDarkMode", nil, 3.0) as! Bool)
}
- (void)testSendMessageToApplicationUnderTest {
    app.launchArguments = [config automationLaunchArgumentsReset];
    [app launch];
    APLAutomationSendMessage(@"SetDarkMode", @YES, 3.0);
    XCTAssertTrue([APLAutomationSendMessage(@"GetDarkMode", nil, 3.0) boolValue]);
}

Get an instance of your subclass in your XCTestCase. A good place to do this in the setUp method.

Apply the result of method to XCUIApplication launchArguments property.

Once your app is launched, the configuration you set in will be applied before executing each test case.

See also and methods of .

You can apply configuration to the app after it has launched using the , and methods of . You can read the configuration from the app under test using the method.

Under the hood, the , , and methods use the and functions introduced in the .

Use the function in the app under test to declare a callback. The callback will be invoked anytime a message is received from the XCTestCase. Best practice is to wrap the function in #if DEBUG to ensure it's not included in an App Store build.

Use the function in your XCTestCase to send a message and wait for a reply from the app under test.

The and is compatible with both iOS Simulators and physical iOS devices.

The plist parameter accepts any object that is , or nil. This also applies to the result returned from . The size of the property list once serialized, must be less than 65535 bytes, otherwise an will be thrown from the XCTestCase. In practice, keep your property lists to just a few hundred bytes. Larger property lists will result in significant transmission time (tens of seconds).

APLConfiguration
APLConfiguration
automationLaunchArguments
automationLaunchArgumentsReset
automationLaunchArgumentsWithAction
APLConfiguration
automationSendConfiguration
automationSendConfigurationReset
automationSendConfigurationWithAction
APLConfiguration
automationSendReadConfiguration
APLAutomationMessageReceivedBlock
APLAutomationSendMessage
APLAutomationSendMessage
APLAutomationMessageReceivedBlock
APLAutomationSendMessage
property list compatible
APLAutomationMessageReceivedBlock
AppfigurateLibraryException
Create instance of APLConfiguration subclass
automationSendConfiguration
automationSendConfigurationReset
automationSendConfigurationWithAction
automationSendReadConfiguration
APLAutomationSendMessage
APLAutomationMessageReceivedBlock
next section
APLConfiguration
APLConfiguration
allowInvalidSignatures
Objective-C example
Swift example