keychain-swift icon indicating copy to clipboard operation
keychain-swift copied to clipboard

Cannot make it work when running UI Tests on iOS 10 / XCode 8

Open cdepace opened this issue 8 years ago • 4 comments

The library works fine when I run the app in the simulator for development, but if try to run UI Tests all the keychain.get and keychain.delete calls keep on failing. I followed the procedure reported on http://evgenii.com/blog/testing-a-keychain-library-in-xcode/ but it seems applicable to Unit Test only. When I select the UI Test target I see no "Allow testing Host Application APIs" as for the Unit test target. I need to reset the user session stored in the keychain after each test and I cannot figure it out how to proceed. Ps. I placed a breakpoint in:

  @discardableResult
  open func clear() -> Bool {
    var query: [String: Any] = [ kSecClass as String : kSecClassGenericPassword ]
    query = addAccessGroupWhenPresent(query)
    query = addSynchronizableIfRequired(query, addingItems: false)
    lastQueryParameters = query

    lastResultCode = SecItemDelete(query as CFDictionary)

    return lastResultCode == noErr
  } 

and the lastResultCode value when returning is -34018 (not sure if I'm prompting it correctly,thou)

cdepace avatar Oct 18 '16 15:10 cdepace

Hello @cdepace, thank you for reporting the issue. Unfortunately, I could not reproduce it. I created a new iOS app that writes to Keychain and then displays the key on the screen. Then I created a UI test that verifies the text. The test passed. Is there anything else that I am missing here?

Xcode 8.0 (8A218a), iOS 10 simulator.

Please find the demo project attached.

UsingKeychainWithUiTests.zip

evgenyneu avatar Oct 23 '16 00:10 evgenyneu

Hello @evgenyneu, thanks a lot for the archive I will try it as soon as possible.

For the records, my workaround was to trigger the session cleaning using launch arguments in the UI Test:

override func setUp() {
        super.setUp()
        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false
        // communicate to the app of resetting keychain
        app.launchArguments = ["UI-Test-ResetKeychain"]
        app.launch()
    }

then in the app delegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        // Reading arguments coming from UI Tests
        var arguments = ProcessInfo.processInfo.arguments
        arguments.removeFirst()
        print("App launching with the following arguments: \(arguments)")
        // Always clear the defaults first
        if arguments.contains("UI-Test-ResetKeychain") { 
            if !keychain.clear() {
            log.error("Not possible to clear the keychain")
           }
        }
 }       

cdepace avatar Oct 24 '16 16:10 cdepace

Thank you for sharing your solution. Let me know how it goes.

evgenyneu avatar Oct 24 '16 19:10 evgenyneu

@cdepace what you can (probably) do is to add a test host app and set it as host application in your test target. Also make sure the host app should've keychain sharing capability turned on(which will eventually add a keychain entitlement). This way at least I made sure (in one of my framework) the unit tests execute in iOS 10 simulator.

Hope this helps!

manojmahapatra avatar Nov 02 '16 16:11 manojmahapatra