Linker error when accessing application module in UI tests in Xcode 7.1
Asked Answered
I

3

39

I'm trying to implement some UI tests in my project. Everything goes fine as long as I keep it simple: record the test case, add some asserts, then run the test. This works fine, however when I try to access the application module from inside my test, the linker throws an error (See below):

In the application source file:

func foo() {
   assert(true)
}

In the UI tests:

import XCTest
@testable import MyApp

func testExample() {
    foo()
}

Error:

Undefined symbols for architecture i386: "MyApp.foo () -> ()", referenced from: MyAppUITests.MyAppUITests.testExample (MyAppUITests.MyAppUITests)() -> () in MyAppUITests.o ld: symbol(s) not found for architecture i386 clang: error: linker command failed with exit code 1 (use -v to see invocation)

Undefined symbols for architecture x86_64: "MyApp.foo () -> ()", referenced from: MyAppUITests.MyAppUITests.testExample (MyAppUITests.MyAppUITests)() -> () in MyAppUITests.o ld: symbol(s) not found for architecture x86_64

I have found similar issue reported here: https://forums.developer.apple.com/thread/20609 but no solution. Seems to me like the @testable simply doesn't work correctly. The guy on the developer.apple.com tried to workaround by adding the Test Host and Bundle Loader in the settings, but I don't think this is the correct approach. I think the @testable should just make everything work, and it doesn't look like it at the moment. Any help appreciated!

Ion answered 17/11, 2015 at 10:48 Comment(3)
You should not be accessing the application module like this from your UITests.... but if you really want to (please don't) you can check the box for target member ship in the file inspector. I would think that @testable does not work in UITests, cuz you should not be accessing raw functions like this.Kingfisher
@Kingfisher can you elaborate on why not? For me this is a perfectly fine scenario, especially if you have some static variables or methods to check in your tests. As for your suggestion to check target membership, this is exactly what I wanted to avoid by using @testable.Ion
For Android UI Tests, it is perfectly fine to access application code from the tests. For Android UI Tests, you cannot only access static variables, but also arbitrarily modify the app state at runtime. I agree that you should not do this all the time, but it is a valid usage scenario and a powerful feature.Kimmy
H
65

@testable import MainModule won't work for UI test, though it would enable code completion (may make you feel it works). It's designed only for unit test so far. And it would lead to build failure, something like:

ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

The workaround is to add the source code file to UI test target as well, then it will work out of the box (even without @testable import).

File Inspector -> Target Membership -> check UI test target (in addition to main target)

Hope Apple will fix it soon so that we can have a cleaner way to use it.

Haymow answered 13/4, 2016 at 19:30 Comment(1)
@JingLi Thanks a lot! I had a same issue when I was trying to add a unit test target to a macOS bundle.Branch
V
6

The UI tests are a separate module from the app, therefore not run inside your app as a logic test would. The only way for them to share code is to compile in all the app files you need to share between the two modules. Check this blog for how you can achieve that, https://www.bignerdranch.com/blog/ui-testing-in-xcode-7-part-1-ui-testing-gotchas/

Also found a radar filed here, https://openradar.appspot.com/23116258

Ventriloquy answered 30/11, 2015 at 10:6 Comment(0)
S
3

@testable import <yourApp> could actually be causing this bug. Just take out the line. It isn't needed for UI Tests.

"UI tests run outside your app in a separate process. You can’t access app code from inside a UI test - that’s intentionally part of the design. Use unit testing for tests that need to access the app code and UI tests to automate user interaction testing"

Notice at 6 minutes in, @testable isn't used by Apple Developers. https://www.youtube.com/watch?v=7zMGf-0OnoU&t=1316s

Susannahsusanne answered 3/8, 2017 at 9:4 Comment(2)
The bug happens without @testable as well. As noted in other answers, really, UITests weren't meant for accessing raw code - that's what Unit Tests are for - so, you're right, @testable isn't (or shouldn't be) necessary in UI testing. However, sometimes you just need to access that raw code (eg, dropping Core Data info before each test run...)Vernacularize
Yea, it would be nice if they let the modules talk for different cases.Susannahsusanne

© 2022 - 2024 — McMap. All rights reserved.