How do I access my swift classes from my UI tests?
Asked Answered
U

4

10

I have a UI test like so :

    func testHome(){
         if(isRedOrange.clear()){
                //code
            }
    }

How would I access my isRedOrange.clear function from my isRedOrange.swift file from my UI tests?

Updraft answered 11/8, 2018 at 12:59 Comment(1)
Possible duplicate of #37755196Fortunate
H
25

UI Tests are black boxed, so you cant have access to your code.

You can use @testable import in Unit Tests, so full access will be provided. When you're running UITests this is not working, because during a UITest your test class cannot access your app's code.

From Apple's Docs:

UI testing differs from unit testing in fundamental ways. Unit testing enables you to work within your app's scope and allows you to exercise functions and methods with full access to your app's variables and state. UI testing exercises your app's UI in the same way that users do without access to your app's internal methods, functions, and variables. This enables your tests to see the app the same way a user does, exposing UI problems that users encounter.

You must achieve everything using .tap()'s on elements. .accessibilityIdentifier will help you to get the right element

Hardness answered 11/8, 2018 at 19:57 Comment(1)
It really surprises me that one can't define the data or flow of the app from the test suite. What Apple seem to be pushing people towards is what I think of as integration testing, whereas I want to write atomic tests which will test parts of the app's UI based on a supplied view model, and I don't want to have to re-write my queries if I happen to change the app flow.Holm
Q
9

Goto projects settings -> Select uitests target -> build phases tab -> add your swift file to compile sources

Quentin answered 11/8, 2018 at 15:58 Comment(5)
That worked for. Just wanted to use some existing model structs to pass some test data in.Goiter
I was wondering if this really works. As I understood Ui Tests and the app are like 2 different applications running side by side. So will adding a file to a second app will remove the syntax errors? yea... but will have any impact on the main app ? won't this just execute code @ the "ui project" rather than having any affect in the app we are testing?Brookebrooker
@JoãoSerra that's correct. The UI tests and the app are compiled separately, so the tests cannot, for instance, directly call a function within the app. You can, however, make source code available to both the app and the tests (as this answer explains). Then the tests and the app can share algorithms and data structures. They still run separately though.Adamant
Another way is to open the specific files to use with the test target, go to the File Inspector (right panel of Xcode) and under Target Membership tick the test targetDifficulty
@Difficulty If I do that I get build errors "Undefined symbol: ...".Profusive
R
3

You need to import your main module (project) into tests:

  • Ensure you've set ENABLE_TESTABILITY in Build Settings of the main project target to true.

enable_testability

  • To import it into tests, call @testable import MAIN_TARGET_NAME in your UITests file.

enter image description here

Regulator answered 11/8, 2018 at 13:31 Comment(8)
Sorry but where should @testable import MAIN_TARGET_NAME be located at? below import UIKit? Also, upon doing that my class is not showingUpdraft
im using swift .Updraft
it says No such module 'InternetAvailabilty.swift'Updraft
The same way as you import the module UIKit using import UIKit, you will use @testable import YOUR_APP to import your main target. Also, if you just have a global function func clear(), you just call it with clear(), you never call the filename in SwiftRegulator
what is you target's name? not the Swift file, but the target in Xcode?Regulator
its called hd-teamUpdraft
I edited my answer with some pictures to make it more clearRegulator
This works for Unit Tests, but not for UI Tests.Transmigrate
F
-2

The question makes no sense. You don’t access any of your app’s code in a UI test. If you want to access your code, write a unit test.

Fortunate answered 11/8, 2018 at 20:12 Comment(2)
In my case, I needed to mock NSOpenPanel to provide a consistent output in UI tests, so I defined a protocol and extended NSOpenPanel to adopt it. I also defined a mock class in my UI Test target that also adopts the protocol. The protocol definition needs to be available to both the app and the UI tests. I just moved the protocol to its own source file and set its "Target Membership" to both app and UI tests.Transmigrate
Wait, I realized can't inject my mock class from the UI test target anyway... I have to somehow determine whether I am being UI-tested from the app itself (and use either NSOpenPanel or mock its behavior and returned URL). The app code really is inaccessible from the UI Test target. Makes perfect sense though, since UI tests are based on macOS's accessibility features...Transmigrate

© 2022 - 2024 — McMap. All rights reserved.