Swift 2 + Xcode 7: Unit Testing Access Made Easy!!!!

One of the biggest challenges to Unit Testing in Swift was the initial setup. Before Swift 2, you either had to make everything public or remember to add all your files to the testing target (more on this in my blog post on testing in Swift here). But as of yesterday, this annoying testing issue has been elegantly solved!

All you need to do is:

1. Create Your Internal Class

I just created a super simple internal Model object in my brand new TestingTests project with one function:


Again, notice that I’m not adding this model to my test target and not making the class or my method public!

2. Import with @testable

In your test target, just import the module you want to test using the @testable keyword:


3. Test Away!

That’s it, now you can use all the internals of your class for testing purposes 🙂


Thank you Swift team!

Enjoy the article? Join over 20,000+ Swift developers and enthusiasts who get my weekly updates.

  • Behinder

    Great to know. I still try to understand this whole testing stuff in obj-c

  • andreamazz

    Hi Natasha, thanks for sharing
    I’m so glad they added this, adding the public access control to stuff that should have been private was bothering me quite a bit, although it led to interesting discussion on what should be tested, and how.

  • Great! Thanks for sharing.

  • Pingback: Michael Tsai - Blog - WWDC 2015 Links()

  • Dung Nguyen

    Thanks for your sharing Natasha.
    It would be better if you have a menu bar on your blog. I had alots of difficulties on finding older page.

  • raul_mpad

    Thank you so much for the testable keyword solution to my problems.
    I just had a problem with the code coverage’s new feature in Xcode 7 and now it’s gone after so many days trying to figure it out what was happening…

  • jeremychone

    I have xCode 7 beta2, and somehow, even when @testable …, I still need to set my .swift target to the test target? I am on a command line Mac OSX project.

    • Nicole Lehrer

      Thanks Natasha for your blog and the helpful info. I am having the same issue as @jeremychone:disqus for an IOS project.

      • Nicole Lehrer

        This was my bad – I was using
        @testable import swiftFileName
        instead of
        @testable import moduleName
        and it works just as Natasha describes.

        • jeremychone

          Hum, I had the moduleName one, but still had add my files to test target. I will give it another try.

          • Zacharias Beckman

            Same problems here. Seems like it’s not quite ready for prime time. I tried creating a brand new testing target, adding one new test case, made sure “Enable Testability” is YES, but no go. Definitely not working… perhaps in beta 6… (crossing my fingers! This would be a fantastic feature!)

    • Victor Ji

      Same problem with Xcode 7 beta 2.

    • Mark Anders

      Hi @jeremychone:disqus , in the project settings/Build Settings in the Packaging section for your app, did you set “Defines Module” to Yes?

  • Thanks for writing this little tutorial up, Natasha. IMO this would be a little more useful if the project wasn’t named TestingTests, kind of gets confusing with the actual testing code you’re implementing

  • Pingback: @Testable keyword in Xcode 7 - iOS Unit Testing()


    I am using Xcode 7 beta4, and on adding the @testable keyword before importing the module am getting the ‘No such module ‘ . Though after the @testable keyword, am able to access all the internal swift classes, but it throws this error while compiling for testing. My product module name is set to target name and I have checked this part for main product target. How should I solve this problem ?

    • Make sure your Enable Testability option is set to yes in build settings – http://stackoverflow.com/questions/30787674/module-was-not-compiled-for-testing-when-using-testable


        Hi, Have made the changes initially but there’s no way it is ready to accept the existence of the module. Attaching two more screenshots.

        • euclid1767

          Try removing the Test Target entirely and readding. I haven’t dug down to figure out the exact cause, but I had the same problem and this seemed to resolve.

        • Product Name is the solution. I had
          different product name than the folder names. Problem solved

    • Suragch

        This method will not work if your project is using both Objective-C and Swift. This method is for only total swift based project. That’s what I found in my project and reading few other blogs

    • Dominic Frei

      Even though you are talking about a beta and Xcode 7 is now stable, I had that problem within the release version of Xcode 7, too.
      In case someone stumbles upon this post in the future: A clean did help!

  • Christopher Sanders

    Thank you for this! I really needed this!!!

  • Tyler Williamson

    Unfortunately, my classes that are not members of my tests schema are not visible from within their own module. Use of undeclared type ‘ClassName’ from within its own module! Ugh!

  • Dheeraj

    How can I test the private methods in a class?

    • You shouldn’t test private methods. But you can test their side-effects in the internal / public methods that use them.

      • Dheeraj

        Okay, thanks for replying. Can you suggest few ways to test the code effectively?

        • Steve

          Google is your friend.

      • Zacharias Beckman

        I agree – testing should generally focus on public APIs/methods… BUT, technically, with @testable you can now test private methods (requires Xcode 7, Swift 2, and some creativity). There have been a few cases where I’ve really, really wanted to know what would happen if, say, a private internal method returned something that it would not normally return. Subclass it, override the method, inject the mock object, and there you go – use @testable if needed to get easier access.

      • Chad Nelson

        Why shouldn’t private methods be tested?

        • Steve

          Because testing private makes refactoring a problem. Treat your objects like black boxes when testing and then you will be on the right track.

          • DamienSan

            I don’t see in what it makes refactoring a problem. On the opposite, the unit testing will ensure your refactoring will be done correctly.

          • Steve

            Well let us know how that works out for ya then!

          • DamienSan

            Well on young & lagging behing languages like Swift: it’s a mess.

            On mature language like Erlang: it’s a bliss. There are 2 differents frameworks included, EUnit for white box testing, Common Test for black box testing.

            Each are optimized for a specific use case and covers everything.

      • DamienSan

        You should test private methods too: it’s called white-box testing (as opposed to black-box testing). A lot of internal processing can happen in private scope and you need to ensure that each step is going right.

        The scope of the function shouldn’t be used as a decision for not testing it.

  • Nalin

    Thanks for the simple but very helpful article.
    Btw if anyone else got a similar error like I did “Failed to import bridging header”, I got it working with this change https://github.com/CocoaPods/CocoaPods/issues/2695#issuecomment-72873023

    • uma maheshwaran

      I got this issues.how to solve this?

  • Peter Ivanics

    extreme helpful, thank you! <3

  • Daniele Bernardini

    By the way, if you have problems with some class now and done do a good ol’ clean and it will go away

    • Anthony Edgar Bernardo Savioz

      Thank you!

    • Rob_McB

      +1 Thank you for that advice also. Just spent 20 minutes puzzling over this.

  • Oleg Novosad

    Hello, I encountered issue: “Cannot import module being compiled” when I tried to use: @testable import ModuleName

    How can I fix it? Help please!

  • Drew Pitchford

    So I’ve done this, but I get this error:

    Undefined symbols for architecture arm64:

    “type metadata accessor for digitaldoorviewer.User”, referenced from:

    It’s a linker command error. Have you seen this before and how were you able to fix it if you have?

    • Kevin Hirsch

      I had the same issue. Turns out you can’t use your app code for UI Tests: https://github.com/Quick/Quick/issues/415#issuecomment-153885307

      • Drew Pitchford

        Yes, I’ve seen that link. These are not UITests. They are Unit tests. It’s a really annoying problem.

        • Lars Blumberg

          I’m having the same problem. Linker error with “type metadata for XXX reference from: XXX”. Did you find a solution?

  • Scenario:

    * iOS application with a mix of ObjC and Swift classes.
    * Unit test class written in ObjC.

    Is it possible for the ObjC unit test class to access the public Swift classes in the main target (I don’t think assigning them to both the main target and the ObjC test target would work)? I’m able to import normal ObjC classes that aren’t assigned to the test target into the unit test class and I’m able to create a Swift unit test class and import ObjC classes that similarly don’t have test target membership into it, but not for the ObjC test target importing Swift classes in the main target.

    The main target does have module defines module set to YES and its module name is set, which is how I’m able to import the ObjC classes into the Swift based unit test class.

    #import “MainTargetModuleName-Swift.h” won’t work since this auto generated header is the value for the SWIFT_OBJC_INTERFACE_HEADER_NAME build setting on the main target, and the test target doesn’t know about it.


  • TestingTests must be the name of the Product Module Name that can be different from the folders name as image show above. That can lead you to search why don’t recognise the ‘TestingTest’. Please add a warning about that.. to save time :)X Very good post:)X Thanks

  • Nicolás Miari

    I still don’t understand why we have to perform this (admittedly, east) step for the unit tests target, but the UI tests target works right out of the box.

  • goblin

    It worked for iOS than I tried with Command Line Application but it didn’t work out. Some linker problems

  • Thanks for this lovely simple intro Natasha,
    I have referenced it in my GH project


  • Ace Green

    Thanks for the post. In my case, the class is recognized but my functions are recognized as if they are private

    for example:

    func queryCurrentValue(completion: (JSON) -> Void) { }

    when I try to call it in my test:

    func testQueryCurrentValue() {

    var expectation: XCTestExpectation = self.expectationWithDescription(“QueryCurrentValue Expectation”)

    ViewController.queryCurrentValue { (resultsJSON) in

    XCTAssert(!resultsJSON.isEmpty, “Query results came back empty”)
    XCTAssert(DataCache.defaultCache.readDataForKey(“(queryLink)”, “Data not Cached”))

    waitForExpectationsWithTimeout(5.0, handler:nil)

    I get the error:
    ‘Use of instance member ‘queryHistoricValues’ on type ‘ViewController’; did you mean to use a value of type ‘ViewController’ instead?’

    Its expecting ViewController as a parameter to that function?

    • Ace Green

      Just an additional note, when I click on BitLive (import) I only see the public classes of my app. Not sure if this is the expected behavior or something is fishy. The “ViewController” class is recognized to it though

  • Qi Mu

    Great, thank you!