Breakpoints set in the testable code are ignored during unit tests. In the test schemes, debug executable is checked.
What might I try to use breakpoints?
Package:
Swift 5.3 Swift Package Manager
Perhaps irrelevant, but a symlink is used to share code between two libraries: one with logic and the other extending XCTest with custom assertions for that logic. This was the cleanest-for-client workaround to the problems Xcode has in importing packages that extend XCTest.
Related
How do you debug package dependancies you have imported into your project? I can't seem to see the code within the packages.
Currently I am using Carthage and you can simply set breakpoints within the code (there are flags that allow you to do this in Carthage).
It looks like you can use editable packages. Not sure how debugging this works though.
Excuse the vague title.
I'm trying to build a package to help me use third-party cloud storage APIs (Firebase Storage for example), adding Combine support, etc. This package does the same thing with CloudKit. Everything compiles fine, but when I import the package module into a separate project of mine, the module is apparently missing some public symbols...
Specifically, the ones wrapped inside of an #if canImport(FirebaseStorage) condition. Since Firebase doesn't support SwiftPM yet, this part of the package behaves as expected in the package project itself; it simply skips compiling that whole bit. I figured that a client project that can import this module would compile it fine.
Aside: What I'm trying to do looks something like optional dependencies. I don't want to have to import Firebase to use this package's other features. I have considered splitting the package into separate sub-packages, each depending upon the particular third-party library I want to use. I might do that anyway. But the problem remains that Firebase doesn't yet support SwiftPM (although I hear they're close).
My issue appears similar to this one. My client project just doesn't seem to see the conditioned symbols, though it can import Firebase and FirebaseStorage just fine! I mean that the generated module header is missing them entirely, preventing my client project from compiling when I use them.
It seems to me that the compile condition never leaves the package's own scope of dependent targets. Is this the case? Or am I missing something obvious? I had always assumed that Swift Packages just import and compile the Swift source files into named modules, but now I think that is not so.
Is there a way to build code into a Swift Package that compiles only when the client can import a third-party module that does not yet support SwiftPM? Or does conditional compilation not work that way?
EDIT: Here is the Swift documentation on conditional compilation, for reference.
(Answer from experience in Apr 2020)
It looks like I'm just misunderstanding the compile order.
Importing my packaged module (let's call it CloudStorage) declares a dependency in the client project to that module. Before the client project can compile with its other dependencies, CloudStorage needs to compile without the main project's dependencies. Since CloudStorage doesn't know anything about those dependencies, canImport for those dependencies evaluates to false.
This may have changed in a later version of Swift. I've yet to try again.
canImport checks whether the module name provided can be imported. For swift packages, this evaluates to true if you have provided the module as a target dependency in the package manifest and all of its associated target dependency condition are satisfied.
The benefit of this is this allows you to write code in a platform agnostic way and let your package manifest take care of platform support.
Let's say I have Firebase as a dependency in my target:
.product(name: "Firebase", package: "firebase-ios-sdk", condition: .when(platforms: [.iOS, .macOS, .tvOS])),
I can write my code that depends on Firebase with canImport. Suppose in future firebase-sdk started supporting another platform, I can add the platform to my availability condition and start supporting that platform in my code as well.
But if you don't have the module listed as dependency, even if your client app can import the module, this condition will always evaluate to false. This is due to the sandbox nature of swift package build system and all your package targets are isolated so that consuming client's build settings doesn't affect your package target.
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.
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.
I'm new to both Monotouch and Monodevelop. Trying to get started with NUnit and I'm having a lot of trouble -- none of the sketchy references I can find on line seem to match what I'm seeing in the UI (MonoDevelop 2.4 on Mac OS 10.6). I've tried:
Adding an "NUnit assembly test collection" project to my solution.
Adding an "Empty MonoTouch Project" project to my solution, and then adding the NUnit assemblies to it, and adding my main project as a reference.
Adding a C# "Empty Project" to my solution, and adding NUnit, MonoTouch, and my own project as references. This produces a build error complaining that "'[test project name].exe' does not contain a static 'Main' method suitable for an entry point."
(1) produces a strange sort of project to which I can only add assemblies -- no references and certainly no tests.
(2) and (3) behave pretty much identically:
First, a build error complaining that there's no static 'Main' method. I can fix this by changing the compile target to "Library" in the Build -> General project options.
Next, when I try to run the tests (from the Unit Testing tab), it says it's running them using the "Debug|iPhoneSimulator" configuration.
The Test Results panel shows this "running tests" message, and never any other output.
The counts stay at "Tests: 0 Failed: 0 Ignored: 0".
Clearly I'm doing something wrong here, but what am I supposed to be doing?
Just for grins, here's my test.
using System;
using NUnit.Framework;
namespace mynamespace
{
[TestFixture]
public class NavItemTest
{
[Test]
public void TestAll()
{
Assert.AreEqual(4, NavItem.all().Count);
}
}
}
In case you missed it, there is now a NUnitLite runner available for MonoTouch which is designed to work for UI agnostic code and executed on devices (or simulator).
See: .NET Unit test runner for iOS
Have written up a few details on what we have found to be best practice so far. You can find it here: http://ben.phegan.name/index.php/2011/02/28/monotouch-and-unit-testing. Would be happy to hear other ways of doing this.
Short answer:
Add NUnit project to normal solution
Add MonoTouch assemblies as references
Write tests, avoiding testing anything that uses monotouch.dll (design patterns to abstract this stuff).
Win!
I had the same problem:
This produces a build error complaining that "'[test project name].exe' does not contain a static 'Main' method suitable for an entry point."
Fixed by going into Project -> [Project name] Options -> Build General. Changed Compile Target to Library. I hadn't made a Main-method class yet, but will probably later; so then I'll change back.