Module Was Not Compiled for Testing' When Using @Testable

Module was not compiled for testing' when using @testable

In your main target you need to set the Enable Testability build option to Yes.

As per the comment by @earnshavian below, this should only be used on debug builds as per apple release notes: "The Enable Testability build setting should be used only in your Debug configuration, because it prohibits optimizations that depend on not exporting internal symbols from the app or framework" https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Chapters/Introduction.html#//apple_ref/doc/uid/TP40001051-CH1-SW326

Module was not compiled for testing @testable import error

I found out what was wrong.

Just turn off the "Run" flag from the Target:

Target Running flag

Carthage builds the Release configuration with ENABLE_TESTABILITY=false which causes tests target build to fail.

No such module when using @testable in Xcode Unit tests

The answer that worked for me

The answer was that I had some errors in my project that was making the build fail. (It was just your standard every day bug in the code.) After I fixed the errors and did another clean and build, it worked.

Note that these errors didn't show up at first. To get them to show up:

  • Comment out your entire Test file that is giving you the "No such module" error.
  • Try to run your project again.

If there are other errors, they should show up now. Fix them and then uncomment your Test file code. The "No such module" error was gone for me.


In case this doesn't solve the problem for other people, you can also try the following:

Clean the build folder

Open the Product menu, hold down Option, and click "Clean Build Folder..."

Sample Image

Make sure that Enable Testability is set to Yes

In the Project Navigator click your project name. Select Build Settings and scroll down to Build Options. Make sure that Enable Testability is Yes (for debug).

Sample Image

Delete and re-add your Tests target

If you have done the other things my guess is that you probably don't need to do this. But if you do, remember to save any Unit Tests that you have already written.

Click your project name in the Project Navigator. Then select your Tests target. Click the minus (-) button at the bottom to delete it.

Sample Image

Then click the plus (+) button and choose iOS Unit Testing Bundle to add it back again. As you can see, you can also add a UI Testing Bundle in the same way.

A few other ideas

  • Make sure that all required classes are members of your test target.
  • Make sure that you have added all the required libraries.
  • Make sure that the module name is written correctly (see this answer).

Or...

Leave a comment or answer below if you found something else that worked.

Related

  • How to do a Unit Test in Xcode
  • Xcode UI Test example

What's happening behind the scenes in XCTest's @testable?

To answer your question, for debugging purposes, you can actually use this. Let's say you have a workspace MyAwesomeWkspace and a project inside MyAwesomeProject.

Now, create a new framework aka module called MyAwesomeModule. Inside that module create a non-public class called Person.

If you try to use the class Person inside MyAwesomeProject by doing import MyAwesomeModule and then something like let p = Person() you will have an error.

But if you do @testable import MyAwesomeModule, the magic happens and you can now use the class.

Basically @testable allows you to test things that you didn't declare public. The annotation only works with import as you can see it here.

So in order to work, the target is compiled with -enable-testing so that you can have access to non-public members. At least based on what's here

Because, by default, the debug build configuration is compiled with -enable-testing, the example I showed you will work. But if you change the build config to release, you'll see an error saying Module .. was not compiled for testing since the release config is not built with the flag.

The Swift access control model, as described in the Access Control
section of The Swift Programming Language (Swift 4), prevents an
external entity from accessing anything declared as internal in an app
or framework. By default, to be able to access these items from your
test code, you would need to elevate their access level to at least
public, reducing the benefits of Swift’s type safety.

Xcode provides a two-part solution to this problem:

When you set the Enable Testability build setting to Yes, which is
true by default for test builds in new projects, Xcode includes the
-enable-testing flag during compilation. This makes the Swift entities declared in the compiled module eligible for a higher level of access.
When you add the @testable attribute to an import statement for a
module compiled with testing enabled, you activate the elevated access
for that module in that scope. Classes and class members marked as
internal or public behave as if they were marked open. Other entities
marked as internal act as if they were declared public.

More here

Late edit: One of the cool parts of swift is that is open source. So if you want to dive deep into the "magic", check it out: https://github.com/apple/swift

How to enable testability for Framework in Release mode?

I created a sample project for you. Your setup might be different, but this sample project will demonstrate how to test the release url and debug url, go through the edit scheme settings. Here is the link https://github.com/borg666/ios-multi-scheme-config-example

Basically the trick is to have another scheme in which debug flag is disabled and it runs a separate test file where you can test the release url, By doing this you are free to enable testability on this scheme.

You might consider having user defined variable for the url, with my example you can achieve more complex configurations.

Strange compilation error with @testable import

Project and target names can contain special characters (like spaces or dashes), but module names can not. By default, Xcode generates the module name from the target name by replacing invalid characters with an underscore.

Therefore, in your case

@testable import My_Project

would fix the issue. Alternatively, assign a custom “Product Module Name” in the build settings of the target.

There is no need to rename the entire project (or target).

Jenkins build failed with Xcode if project have test cases

In jenkins, configuration was Release (by default) which was unnoticed by me, after replacing it to Debug my build is succeeded.

Reference Image:

Sample Image

Reference Doc:

https://plugins.jenkins.io/xcode-plugin/


Special thanks to Scriptable for giving time and efforts for solving the issue.



Related Topics



Leave a reply



Submit