Using XCTest files in multiple projects - swift

The app I work on takes too long for comfort to compile and to run tests on, so I started creating "feature development projects", which are small projects where I do most of the development (while already under version control for the main project) until I integrate the feature into the project by dragging the new classes and tests into the main xcode project. An issue I have run into is making the main target visible to test files in a universal manner. Lets say we have a project named MyMainProject and a feature project named FeatureProject. For testing in FeatureProject I would have to import everything from the main target (of that project) by doing:
#testable import FeatureProject
That of course won't compile once I integrate the new tests into MyMainProject, which would expect the following (to import the main target of the latter project):
#testable import MyMainProject
My first instinct was to play with the preprocessor to solve the issue, but maybe there is a more elegant way to solve this?
Additional Infromation:
I have Allow testing Host Application APIs checked in General->Testing

Related

C++ Boost Test, package structure, and Eclipse project settings

I'm using C++98, and besides the standard library, I only have access to an old version of Boost (which thankfully has Boost Test). The documentation though is daunting, long, and I just don't know where to begin.
I have some experience doing unit testing in Java (and I'm looking for unit testing in C++), and I've seen test packages that contain the unit test code separate from the src package, and I also saw Where do you put your unit test? as well as Unit Testing with Boost and Eclipse. Their suggestions vary, and present reasoning for different packaging structures for separating test code from production code, or having them together.
Before I even started looking into Boost Test, I created this structure within Eclipse (perhaps erroneously):
-- ProjectName
|-- Debug
|-- src
|-- test
and I wrote another main method to run test functions. Eclipse didn't like that, because I had two main methods in the same project. I fumbled around through Project Properties and didn't find anything useful for separating my production code from test code when building (linking, really). My temporary fix was to just use g++ in the terminal and ad hoc compile just my "test" code.
I found something suggesting on Boost::Test -- generation of Main()? that Boost actually generated its own main method, so this is currently my plan of attack for unit testing, especially for having a library of testing tools already available.
What is the conventional way of organizing unit tests for C++?
How do I get started with Boost Test? (Boost is already installed)
Is there anything I need to change in Eclipse to be able to run my Boost unit tests separate from my production code within the IDE? (One of the nice things about IntelliJ, with Java, is how it'll automatically run any main method you like with a click) -- The goal here to be able to build and run my tests within Eclipse.
Should my tests be in a separate Eclipse project? (this was suggested in an answer to the second SO question I linked)
Edit: I found this article for an introduction to Boost Test, but it doesn't discuss how it can be handled within an IDE setting.
I figured out how to do this on my own, and I'll document my solution for others who are just starting with C++ as well and need to do testing of their code. There currently is no good introduction anywhere that I could find. Here are the resources that I used though (and found useful):
C++ Unit Testing With Boost Test which introduces Boost Test in a much better fashion than Boost's documentation.
Where do you put your unit test? which discusses the most conventional ways of doing tests with C++.
unit test in eclipse g++ which discusses Eclipse build configurations which allow testing
The C++ convention for testing is like that of other coding languages, just write your tests in a directory called test under the project. Using Boost Test requires that you link the unit test framework: -l boost_unit_test_framework which in Eclipse:
Right click on your project, go to Properties, C/C++ Build, Settings, Tool Settings, GCC C++ Linker, Libraries, and add the library name boost_unit_test_framework (add -mt to the name if you require multithreading; additionally, once the testing build configuration exists, you can go back and choose just that configuration to link the library -- it'll reduce the size of your executable for your other builds).
To be able to run the unit tests in Eclipse separate from your main method, we need to establish a new build configuration. That way, Eclipse knows to exclude your source file with a main method when you're executing your tests.
Click on Project, Build Configurations, Manage..., and select New... and call it Test (or something other than test). Choose your existing configuration so that we'll inherit properties from the production build.
Next, we need to differentiate the build configurations from one another so when we build them, they actually correspond to the production and test builds.
Right click on test, Resource Configurations, Exclude from Build..., and select the builds that represent your production build (i.e. Debug and or Release). Once done with that, right click on your source file with your main method, and exclude that from the Test build.
There's still some things we need to change. We don't have any test code yet, but we still can't run our test build, nor would our test build know about resources existing in src because Eclipse wouldn't automatically include those source files. They're practically invisible to your test code in test.
Right click on your project, go to Properties, C/C++ Build, Settings, Tool Settings, GCC C++ Compiler, Includes, and add the path /.../workspace/ProjectName.
Now to be able to run your test build in Eclipse, it needs to know what executable you're expecting the IDE to run.
Click on Run, Run Configurations..., and looking at your current run configuration, consolidate these settings by giving, for example, a debug build the name "Debug Build", the C/C++ Application "Debug/Artifact_Name", and the Build Configuration "Debug". Next, create a new run configuration, and call it something like "Test Build", set C/C++ Application to "Test/Artifact_Name", and ensure the build configuration is Test.
Now you'll be able to switch between running production code and test code by selecting either the "active" build configuration or running the correct run configuration.
Finally, here's an example of a unit test with Boost Test once all of this is set up:
//unit_tests.cpp
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE someModuleName
#include <boost/test/unit_test.hpp>
#include <src/some_object.h>
struct template_objects {
some_object x;
template_objects() {
BOOST_TEST_MESSAGE("Setting up testing objects");
}
~template_objects() {
BOOST_TEST_MESSAGE("Tearing down testing objects");
}
}
BOOST_FIXTURE_TEST_SUITE(testSuiteName, template_objects)
BOOST_AUTO_TEST_CASE(testCase1) {
x.update();
BOOST_CHECK(x.is_up_to_date());
}
BOOST_AUTO_TEST_CASE(testCase2) {
BOOST_CHECK(x.is_not_up_to_date());
}
BOOST_AUTO_TEST_SUITE_END()
This demonstrates some critical things about using Boost Test:
defining BOOST_TEST_DYN_LINK is recommended; you need to define a way of linking the testing framework before including any of Boost's libraries
you must name the "module" something, doesn't have to be the file name
to get automated setup up and teardown of objects before entering test cases, Boost Test has fixtures, which allow you to call an object's pre-existing state multiple times
the struct is what groups these fixtures, and it's implied that your object should have a well defined constructor and destructor for automatic scoping (if you didn't call new, you don't need delete in teardown)
test suites are just a way of logically grouping your test cases (I haven't tested it yet, but you can probably break up your suites into multiple files for better logical separation)
Additional tidbit: to make Boost Test more verbose, go to your run configuration for the test build, and add the argument --log_level=test_suite.

Swift Package Manager For Development

Question:
Is there a way to create a "development package" with SPM similar to a development pod in cocoa pods that will let me make changes to the actual source project of a dependency package (local path)?
Context:
I'm working on a project that needs to be split into three separate projects. One of these projects is shared by the other two (in this case a data model, shared by a server and a client). For the client, as it uses uikit, I have a development cocoa pod setup that lets me work within the client workspace, make edits to the data model project, and then immediately compile and run. My changes to the data model are then saved in the data model project.
However, for the server, as it is entirely built with SPM, if I want to make edits to the data model project (which I want to have reflected to the client), I currently have to make them in the data model project, then retag it with a new minor version number, clean the server project, and rebuild. I'd love to just set this up like I do with cocoa pods.
If I can't do that, is there at least a way to tell SPM to only update one of my dependencies to a new version number (or to the max version as specitifed within the Package.swift. i.e. minor version of .4, so if I retag from .401 to .402 it would update)? I would have thought I could do this in the Package.pins, but that doesn't seem to work. Not sure why it's not a hidden file if editing it doesn't effect actual changes.
The concept you call "development package" is called Editable Package in Swift Package Manager:
For the packages which are in the editable state, swift build will always use the exact sources in this directory to build, regardless of its state, git repository status, tags, or the tag desired by dependency resolution. In other words, this will just build against the sources that are present.

Xcode 8.1 No such module 'Foo' from unit tests [duplicate]

I recently updated to Xcode 7 beta 5. I tried adding a unit test to an earlier project, but I am getting the error message "No such module [myModuleName]" on the #testable import myModuleName line.
I tried
cleaning the project with Option Clean Build Folder
checking that "Enable Testability" (debug) was set to Yes in the Build Options
deleting the tests target and then re-adding the iOS Unit testing bundle
None of this worked for this project (but I have gotten testing to work in another project). Has anyone else had this problem and solved it?
Please check your Module Name that you try to import with #testable import "ModuleName". The module name should be the same on Target->Build Settings-> Product Module Name
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..."
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).
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.
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
The problem for me was the iOS deployment target of the tests was not set to be the same as the main target. So be sure to check this.
In your test target:
Build Settings -> iOS Deployment Target -> iOS<same as the target you are testing>
So this is how I went about getting my code to work after trying all suggested solutions from prior suggestions.
I set 'Enable testability' to 'YES' in project's Build Settings
I also set 'Defines Module' to 'YES' in my project's Build Settings.
For the regular .swift file(s) within my project, say MyApp, I was going to write test cases for, I have both the main "MyApp" and the
"MyAppUnitTests" Targets checked under Target Membership.
I then selected my unit test file(s), declared the '#testable import
MyApp' at the top, beneath the 'import XCTest', and only checked the
"MyAppUnitTests" under Target membership
And everything worked like charm. Hope this helps.
One gotcha to watch for is that if your module name has a dash character in it - then you will have to refer to it with an underbar instead _. For some reason I suspected this might be an issue and it was indeed my issue.
eg. #testable import Ocean-Swift becomes #testable import Ocean_Swift
Just one other thing, if you do use the #testable syntax be sure to not include your production code in your test target. I've found this will cause inexplicable weirdness.
This sounds to be an error with the build settings of both targets.
You need to ensure that:
ENABLE_TESTABILITY equals Yes for both targets.
The PRODUCT_MODULE_NAME value of the test target should differ from the one of the application.
For those who have scrolled until the last answer and still nothing worked, here is what did it for me after following all other answers advices. I am using Xcode 11:
What caused the issue in my case was that I changed my Product Name
I changed my Product Name in the Build Settings of my main target to "New Name"
I had to re-select the Host Application for my test target
I didn't know that changing the product name would also change the Product Module Name, that is the one used for the module import in my test files. I changed my import as follows:
#testable import New_Name
It worked
I hope it helps
After spending couple of days on this issues finally I make it to work with my project. Problem was in Bridging Header - path in Tests target can't be empty if you are using Bridging Header in your main target
Hope it will save some time for someone.
One other thing to check: If you have an Objective-C project, but are writing unit tests in Swift, make sure the main target uses at least one Swift file!
More info:
I was working on an Objective-C project, but wanted to write unit tests in Swift.
I added a Swift file to the main target to generate the necessary ProjectName-Bridging-Header.h file, wrote my tests and everything was working properly.
Later on I deleted the Swift file because I thought I didn't need it (all of the main target's code is in Objective-C... I was only writing tests in Swift).
I didn't notice a problem until later, after I did a "clean/clean build folder" and the "No Such Module" problem showed up. After some head scratching I added a new blank Swift file and the problem went away.
I've tested it multiple times with/without the Swift file, and it only works with it... so, I'll either need to leave the blank file in the project, convert some Objective-C into Swift, or add some new code to the project written in Swift.
In my case , I had 3 issues.
The first was that I had to specify the import path in :
Target -> Build Settings -> Swift Compiler - Search Paths -> Import Paths
The second was that I was using Pods and I had to import these pods to my tests as well using :
target 'MyAppTests' do
inherit! :complete
end
The third one as that I was using a bridging header in my target , thus I had to specify the bridging header to be the same for the test.
Make sure under the test scheme's build setting, the test target is in the list.
Beside the play button, select the test scheme, then Edit scheme..., go to the Build section, click plus + and select the target you want to test against.
In my case, we have an internal target that we develop with (a few minor differences) and after a merge, it was removed from the test config.
Here is yet another thing to check that is not listed. For me, it had something to do with my team, perhaps because our Team's Agent had not yet agreed to the latest License Agreement! Once I selected a different Team in my Target's General settings, AND then I specified a specific Deployment Target like 12.1 or 11.0, suddenly the "No Such Module" warning went away.
If you have some targets in your project -
check your TARGETS in Module Name that you try to import with #testable import "TARGETSModuleName".
The module name should be the same on:
Target -> Build Settings -> Product Module Name
For example:
I followed the steps above, which worked. However, my project had some more issues. I got this warning and I could not access classes from my main project to test in my test target.
I found that your Test target Product Module Name (YourTestTarget -> Build Settings -> search for product module) cannot be the same name as your project name.
Once I changed the Product Module Name for my test target everything worked.
I tried all the answers here but the red flag would not go away. But I got it to work by just "running" an empty test regardless and it cleared up.
Things I would like make sure are done:
Host Application
#testable import "Module_name" (make sure the module name is correct)
Make sure you deployment target for the test is the same as the project
XCTest does not need to have Target membership
XCode 12.6 beta
I'm not sure what caused this issue for me but cleaning my build folder didn't sort it. Restarting XCode didn't sort out the issue either.
What worked for me was deleting this line: import XCTest, and then retyping it again.
My issue was that the class i wanted to test was supposed to be in a separate module (API Client), but the class was actually a member of the app target and not the framework target. Changing the target membership of the class made the import error go away!
Environment: Xcode Version 9.0 (9A235)
Scenario: Testing an open-source framework.
I had the same problem: 'No such module'.
Solution:
Select the Test target.
Select Build Phases
Add the framework to be
tested via Link Binary...
Here's the test file:
I had this same issue. Cleaning the build folder and restarting Xcode did not work.
What did work for me was ensuring that the setting for "Build Active Architecture Only" of your test target and scheme matches the setting of your app's target and scheme.
XCode 12 Development Beta 3
The error fixed itself after I've built the project for the first time.
This is what worked for me with Xcode 13.1:
In the Locations tab in Xcode Preferences > Locations I had defined a Custom location:
This caused not only unit tests to fail with the dreaded "No such module" error, but also also "Command CodeSign failed with a nonzero exit code" and other warnings and errors.
Changing the setting to Unique:
fixed all problems.
It could also be:
Not set the hosting application for your test target (in the general tab or TEST_HOST build setting)
Missing the app dependency in your Build Phase for your test target.
For me the solution was to rename
#testable import myproject_ios
to
#testable import myproject
after I had updated product name of target myproject-ios in Build Settings/Packaging/Product Name/ from ${TARGET_NAME} to myproject.
This was fixed for me when I changed the Deployment Target from 9.3 to 11.0.
General > Deployment Target > "11.0"
If you are using xcodebuild and find this problem, consider adding in a workspace flag to the build command.
Changed This
$ xcodebuild -scheme PowToonsTests -destination 'name=iPhone X' test
To This
$ xcodebuild -workspace PowToons.xcworkspace -scheme PowToonsTests -destination 'name=iPhone X' test
In build settings test target, check the host testing, it takes the name set in PRODUCT_NAME.
It is that name that you should use in test classes.
I recommand to not change PRODUCT_NAME (match name of the main target)
I think this may have happened because I deleted the example tests.
I removed the Unit test bundle then re-added it as shown in the pictures below and all was well again.
CocoaPods recommends adding inherit! :search_paths to your test target like so:
target 'App' do
target 'AppTests' do
inherit! :search_paths
end
end
Source: https://github.com/CocoaPods/CocoaPods/pull/8423#issue-244992565
Tried all the solutions. Nothing worked. The Xcode build cli failed on a swift package module not found error.
error: no such module 'Apollo'
import Apollo
Removing the Test targets and re-adding them worked for me.
I changed the name of my project as I didn't want my original name for the app to show in the app store. This necessitated a change in my app host, which necessitated a change in the import I made.
Old name: QRCodeTarot
New name: Pointy Hat Tarot
This is the change I made for my host in my version control client.
This meant that in my tests, I needed to change the name of the import to the display name of my app. So even though my project was named QRCodeTarot, I needed to change the import to the display name.
So I went from import QRCodeReader to import Pointy_Hat_Tarot.
The recommendation to make your project name match your test import name is wrong.
The import name should match your project's display name, not your project name

sbt custom task using a class in project

How can I add a custom task to sbt build definition that consumes (uses classes, runs methods etc.) the project sources ? It seems it tries to find them before compiling even.
I need to know why you want to call the methods, since this changes the answer. If you want to do something ...
Build related
Want to use class/ methods which do something build related ( minfiy things, uploaded jar/wars to servers, etc..)
you have to put this in a plugin or you need to put the sources in a project folder.
The code cannot be called from your project
If it is build related, someone has probably dealt with a similar problem and there is probably a sbt plugin already, but if not, then let me know and I can explain creating sbt plugins.
Non-build related
Want to just call / test methods which don't have anything to do with the build cycle.
You can put this in an object in your project called Script (name it whatever), start up console and then import script object and run.
To make this even easier you can make a custom import script for the console which imports all scripts automatically, which you can then run
So for example,
package script
object Script {
def foo = println("I am doing things non-build related")
}
in sbt now run
console
>> import script._
>> foo // prints out "I am doing things non-build related"

Unit testing iphone app withXcode, SenTestCase and C++ dependencies

I have a iphone project with a embedded (for ease of use) open source C++ project in it (meaning its folders are just a group inside the project). Following Apple's tutorial on unit testing Xcode, I could run the tests no problem, provided the only imported files are from Objective-C classes.
However, whenever I run tests that import C/C++ code, the test target fails on tons of "file not found". Any idea on how to solve this, without turning all C/C++ deps on system files?
Try using the .mm extension for your C files, if you're not using it already...
If we're talking about TONS of files, go ahead and try renaming one and see if that removes it from the "file-not-found-pile".
Actually just configuring the search path on the test target solved this. Which is kinda odd, as the project target is a dependency. However, it lead to other issues, which this SO thread took care of it.