How to use one XCTestCase class for many targets - ios

I have white label project (many app's on one source code). Usually I reuse one ViewController for many targets, but to test this ViewController in different targets I must add:
#testable import TargetName
I have tried to create Swift Compiler - Custom Flag with:
-D TARGET_TEST1
-D TARGET_TEST2
and use:
//
#if TARGET_TEST1
#testable import TARGET_TEST1
#else
#testable import TARGET_TEST2
#endif
//
For testing in Xcode it's work, but if I start this on Xcode Server, I have error:
Use of undeclared type 'NameOfClass.swift'
Is it any other options how to provide #testable import for specific test target?

Related

Why can't Xcode find my App for Unit Tests?

I'm fairly inexperienced in iOS. I wanted to write Unit Test for my Cocoapods Project.
My ViewControllers that I want to test are in Pods. When I want to write a unit test, I already receive an error message with
import MyApplication
which says
No such module 'MyApplication'
Note that I used "MyApplication" only as a substitute for orginal name I crossed out in red in the picture.
What is the issue?
EDIT:
code of my test class:
import UIKit
import XCTest
import Pods_MyApplication_Example
#testable import Pods_MyApplication
class Tests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure() {
// Put the code you want to measure the time of here.
}
}
}
To create a test target, on the test navigator, I click on the '+' and then choose 'New Unit Test Target'
I am sorry if there are any information missing. I will add those if there are any!
EDIT2: Changed picture which might provide more information
You must use #testable import to import your app's module for unit testing. You have to supply the name of your application target, Pods_MyApplication_Example, not the name of the project. In your example it will look like the following:
#testable import Pods_MyApplication_Example
And remove the import statement that imports the app target.
Thanks for the responses. I had to add the Plugin/Application that I want to test to the Test Target in my Podfile. So the Podfile looks like this:
use_frameworks!
target "MyApplication_tests" do
pod 'MyApplication', :path => '../'
end
After running pod update I could then import and test my Application.
This error can also occur when you don't have the correct test host appear.
If you see this, and you have selected the iOS Simulator or iPadOS simulator. Make sure that your test target supports that platform.
Select the Xcode project in the lefthand browser.
Click on your test target in the Project's General tab.
Under "General" select your appropriate host application under
"Testing".

Testing fails to import sub dependency - #testable import SubModule - Use of undeclared type 'InternalSubModuleType'

I have a unit test that needs to access internal methods/properties on a module imported by my application target.
E.g.
SubModule.swift
public class SubModuleType {
...
internal let value: InternalSubModuleType
...
}
AppViewController.swift
import SubModule
// do things with SubModuleType
AppViewControllerTests.swift
#testable import App
#testable import SubModule
func testWithSubModule() {
let internalSubModuleTypeInstance = SubModule.SubModuleType().value
// ... run a test dependent on internalSubModuleTypeInstance
}
In this test I receive 'Use of undeclared type 'InternalSubModuleType'' when accessing .value.
I have added the SubModule target to App-Tests "Target Dependencies"
I have set "Enable Testability" to YES for both the App target and SubModule target for the scheme I'm compiling for testing.
#testable import is supposed to allow you to access types marked internal under these conditions. I'm not sure why I'd be receiving this compiler error. I can still use any type that is marked internal in my App target by using #testable but not my SubModule target.
Are you only allowed 1 target to be #testable import in a test target or is there something I'm missing?
using Xcode 9, Swift 3.2
Recreating the Testing target seemed to have done the trick for me.
Simply delete your old Testing target, create a new one and add this target to all the testing files that you have.

Module "MyApp" not found in UnitTest-Swift

Im trying to test some Swift class (#objc class) in my legacy Objc code. I am importing "UnitTests-Swift.h" in my test classes.
Then I get this error:
Module "MyApp" not found in the autogenerated "UnitTests-Swift.h"
This is whats inside the top part of the "UnitTests-Swift.h"
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
#if defined(__has_feature) && __has_feature(modules)
#import XCTest;
#import ObjectiveC;
#import MyApp;
#import CoreData;
#endif
I cleaned the project, checked all the relevant flags ("No such module" when using #testable in Xcode Unit tests, Can't use Swift classes inside Objective-C), removed derived data and so on.. No idea of whats happening, but I m quite sure that #import MyApp shouldnt be there..
Can anyone help me with this?
Just got this issue in my project and after the entire day spent on investigation I finally resolved it.
Basically this happens because you have cyclic dependency between ObjC and Swift. So in my case it was:
Swift Protocol with #obj attribute in a main target;
Swift Class in UnitTest target which inherited this Protocol;
Import UnitTestTarget-Swift.h in any Objective-C class of your UnitTest target
So fairly simple combination leads to this error. In order to fix this you want either:
simply make sure that your Swift Class in UnitTest target is private, so it won't get to UnitTestTarget-Swift.h
or
do not mark your original Swift Protocol as #objc, which will allow you to access your SwiftClass from all ObjectiveC test classes, but those classes won't have any idea about the Swift Protocol.
Because the Swift class to be tested is part of MyApp, you should be importing "MyApp-Swift.h" in the test classes instead of "UnitTests-Swift.h".
You can add a Swift unit test (just create a new unit file and change the extension by .swift).
From that unit test file you can use your Swift classes.
And you can also import that file from your Objective-C unit tests (and the other way around) using the test module bridging headers.
And this would be the default example for your Swift unit test file:
import XCTest
#testable import MyApp
class MyAppSwiftTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
This solution helped me:
Open Tests Target Build Settings
Search for HEADER_SEARCH_PATHS
In the line called "Header Search Paths" set value $CONFIGURATION_TEMP_DIR/myProjectName.build/DerivedSources
Clean and Cmd+U again
Hope it helps!
Many thanks to this article.

Xcode Test not detect my class

I have class named Meal.swift in my project and a unit test
func testMealInitialization() {
// Success case.
let potentialItem = Meal(name: "Newest meal", photo: nil, rating: 5)
XCTAssertNotNil(potentialItem)
// Failure cases.
let noName = Meal(name: "", photo: nil, rating: 0)
XCTAssertNil(noName, "Empty name is invalid")
}
But the problem is that: Use of unresolved identifier "Meal"
#testable import MyApp should work fine. Just remember to set appropriate configurations within Debug for your UITest target.
Xcode 7 adds the #testable import statement to simplify unit testing. At the top of your unit test class files, add the following statement:
#testable import MyApp
Where MyApp is the name of your iOS app. Now the unit test target should be able to find the classes in your app and run the tests. If you get link errors saying that Xcode cannot find your app classes, make sure the Product Module Name build setting's value matches the name you use in the #testable import statement, MyApp in this example.
If #testable import does not work for you, a workaround is to make your app classes members of the unit test target. You can set the target membership of a file in Xcode using the file inspector.
I also encountered this issue, what worked for me is reloading my test file and retyping the
#testable import FoodTracker
then at that point, it detected my FoodTracker classes (Meal class) and errors are gone.
Click on your Meal class. Then on the right side you'll see 'Target Membership' section. Select your test project.
(Xcode 7)
VoilĂ .
In my case, I got error only in the new class I've just made, and it makes me confuse. So, it works by select Unit Test target under class membership of my new class. Or delete the class, make new class again, then select Unit Test Target in that new class.

Add a type function to a Swift unit test target

How does one go about making a type function (defined in an extension) visible to a test target in Swift? If I have the following extension in my project:
extension NSData {
class func XOR(inputData: NSData, withKey key: NSData) -> NSData {
...
return NSData(bytes: output.baseAddress, length: inputData.length)
}
}
the XOR function is visible to the the main project however not in the test target. I also have #testable import MyModule in my test file. (As an aside, interestingly variables which are added in the extension are visible to the test target).
There are three ways (that I can recall) of making the function visible from within your test target.
Add your test target to the target membership of the file containing the extension.
Promote the function from internal (which is implicitly set by omitting an access modifier) to public.
Upgrade to the Xcode 7 beta and use Swift 2's new #testable attribute to import your module. Doing so will implicitly promote your internal variables/methods/etc to public to make them visible from within the tests target.
#testable import MyModule

Resources