Unit testing Swift 2.0, @testable import, and scheme targeting issues

styler1972 picture styler1972 · Aug 28, 2015 · Viewed 12.1k times · Source

I have recently converted my app, and unit tests over to Swift 2.0. I am using @testable import AppName in my Tests.swift files.

Due to an issue with not being able to execute subclasses in multiple targets (see here for the issue), my class EntityName can only be of Target Membership AppName, and NOT AppNameTests.

The problem is, once I switch over to the AppNameTests schema to run unit tests, code in the module AppName can't find the class EntityName and I get

Use of undeclared type 'EntityName'

How do I get AppName to compile when running tests from the AppNameTests scheme without that entity class not a member of the scheme?

Answer

jpsim picture jpsim · Aug 28, 2015

Due to an issue with not being able to execute subclasses in multiple targets

When compiling the same Swift code as part of different targets, the compiler actually generates different classes. So this behaves as designed, but is almost certainly not what you want when running an app's unit tests.

There are two ways I'd recommend you set up your models to allow testing:

1. Public models (recommended)

In your app target:

import RealmSwift
public class MyModel: Object {}

This code should only be compiled as part of your application target, and your unit tests can be set up in the following way:

import MyApp
// should be able to access `MyModel`

Easy enough?

2. @Testable (Swift 2 only)

This approach relies on the @testable keyword introduced in Swift 2.

In your app target:

import RealmSwift
internal class MyModel: Object {} // ACL cannot be `private`

Again, this code should only be compiled as part of your application target, and your unit tests can be set up in the following way:

@testable import MyApp
// should be able to access `MyModel`

Make sure MyApp's build settings have Enable Testability set to YES.

This approach may be preferred to public models if you're building a framework where some internal models shouldn't be accessible from users of that framework.

Realm has a dedicated section of their documentation detailing these common approaches to testing which you can read here: https://realm.io/docs/swift/latest/#avoid-linking-realm-and-tested-code-in-test-targets