Unit testing Command Line Tool target in Xcode - swift

I’ve been struggling for hours trying to find a way to unit test my code. There’s no way to select the main target (MazeGeneratorTests is there b/c I already created it).
Here’s what the Project Navigator looks like (don’t mind the random structure):
After importing with #testable import MazeGenerator, calling anything from the module causes an Undefined symbols for architecture x86_64 error, e.g.:
func testPerformanceExample() throws {
measure {
let _ = generateNodes(rows: 20, cols: 20)
}
}

Edit: I’ve realized that the better way to achieve this is by using a static library (see Library vs. Framework. Here’s an example repo showing how to achieve this: Imericxu/example-testable-swift-cli.
I figured it out. The “Command Line Tool” target is kind of finicky, so you need to separate all your logic into a new Framework target—this comes with a unit test target—and make everything you want to be visible public. Then build and import the framework into your main.swift file.

Related

Build a macos executable from an ios app's source code

I have an iOS app with some business logic. I would like to create an executable which would expose some calculations from the cli, so that I don't have to use the app.
Unfortunately, the code with the business logic that I want to expose depends on lots of other parts of the code, eventually pulling almost all the code. Even worse, it depends on some dependencies that are not available on macos (UIKit or DJISDK via pods).
I just want to write a main.swift, parse the arguments and use some functions from the codebase. What is the simplest way to do that ?
I don't mind if it's ugly (like pulling whole of UIKit in the executable) as long as it doesn't take to much time to implement.
I have two ideas:
remove all dependencies, optionally defining "dummy" classes compiled only for this target for some dependencies. That requires changing a lot of code, but seems to be cleaner.
find a way to pull the whole app in the new target. For example I have a UnitTests target which does that and can run on mac (though an app window appears when the tests run). But I have no idea how to do that.
Any help or guidance to good documentation would be greatly appreciated :)
I did my best to remove all unneeded dependencies, but there was a lot left that couldn't be removed easily. I resulted in using "dummy" classes to be able to compile without providing any logic.
Though it's not super elegant, it's a nice way to cut the dependency chain, and will let me remove the dependencies over time, while still being able to compile.
Ex:
// In common source file
class Business {
func usefulComputation() -> String {
...
}
func unneededFunction() -> UselessObject {
...
}
// In my CLI-target project
// file `DummyUselessObject.swift`
class UselessObject {
// add any function called from source file here, without putting any logic
}
// `main.swift`
let business = Business()
print(business.usefulComputation())

Nrwl build Library Error: File is not under rootDir

The error occurs when I use the library in another library.
Library import is working fine in the app but not working within libraries.
And not able to generate the build of a library.
All libraries are publishable.
Error:
Nrwl.v13 Files Structure within lib folder:
Very difficult to debug. It can be related to circular dependency issue. Are you sure you don't import code from library which import code from the same library ?
A import B
B import A
If this is the case, you should handle this by creating a C library which will be imported by A and B or find a solution for the A or B which will not depend on each other.
Code example will be helpful for help you.
From https://github.com/nrwl/nx/issues/10785#issuecomment-1158916416:
There seems to have been an issue with a migration that was scheduled
for a version but the migration itself was released in another
version, so that might have caused the migration to not run in some
scenarios. That migration should have added the following in nx.json
for anyone having their nx.json extending from
nx/presets/core.json or nx/presets/npm.json:
{
...
"pluginsConfig": {
"#nrwl/js": {
"analyzeSourceFiles": true
}
}
}
Could you please add the above snippet to your nx.json and try again? If after applying the change it doesn't pick
it up immediately, run nx reset and then try again.
This didn't work for me though, so I opened nx issue #11583: library importing other library using wildcard path mapping fails with "is not under 'rootDir'"
I had this issue in one of our monorepo and it was caused by the fact that one of our library's name wasn't valid. We had something like #organisation/test-utils/e2e which we ended up renaming to #organisation/test-utils-e2e (take note of the / usage).

Swift XCTest namespace bug?

I'm wondering if I've found a namespace / XCTest bug in Swift 1.2/XCode 6.4(6E23):
I have a .swift file with a public function encode that takes a few parameters. I also have an XCTest file to test the encode function.
My XCTest file imports my code fine – I'm able to call public functions from it and even the function that is causing me trouble, encode, is autocompleting just fine when I start writing it out. However, when I try to compile it, I can see that it fails (with "Extra argument in call") because the compiler thinks I'm calling Foundation.encode rather than my own.
Changing the name of it makes it work fine, but that is beside the point which is this; Swift is supposed to prioritise your module over the system's so is this a bug or am I missing something?
One thing that could be the issue is this:
Does the swift file in which encode is declared have Target Membership set to both you're test bundle and your main bundle? If not, select the swift file and in the right menu, under Target Membership, select your test bundle as well (it should be a checkmark).

Without #import, does Swift have its own easy way to detect circular dependencies?

#import "whatever.h"
...wasn't perfect, but it was very handy for diagnosing circular dependencies, not to mention enforcing modularity.
You could be certain which classes knew about other classes--with the flick of a finger.
If you had to, you could comment out all the import statements, and add them back one at a time, in order to diagnose a dependency issue. It wasn't necessarily fast but it was dead simple.
And if a class didn't import anything other than the obligatory headers, Son, that's one modular class you had there!
If your project had ten classes that didn't import anything, then you knew that they were ten modular classes--you didn't have to package each class into its own Framework or anything like that. Easy.
But now, with Swift's policy of "everybody knows about everything all the time", it seems like it's just down to personal vigilance to sustain modularity. Personal vigilance is the worst kind!
Am I missing something? Is there a way to do these things easily in Swift?
If you want to modularize your Swift code, you should be using modules!
Creating a new module is pretty simple.
Add a new target to your project by clicking the plus sign here:
Select "Framework & Library" for the appropriate platform (iOS/OS X):
Choose "Cocoa Framework" (or Cocoa Touch, platform dependent) and click Next:
Give your module a name and change the language to Swift (or leave it as Objective-C, it doesn't matter, you can use both).
Add a Swift file to your module:
Add some code to your Swift file. Note, the default access level for Swift is internal which means it can be accessed from anywhere within the module but not from outside the module. Any code which we want to use outside the module must be given the public access level.
public class ModularSwift {
public init(){}
public var foo: Int = 0
}
Be sure to build your module (Cmd+B):
Go back to your original target, import the module and start using its code:
import MyModularSwiftCode
let foo = ModularSwift()
Xcode is perfectly happy:
Now, comment out the import statement and notice the errors:

Xcode unit testing

I have never used Unit Testing and I understand the uses of it but I don't really know when and how to use it.
I would like to know when it's worth it to use Unit Testing, maybe with some examples.
The other answers tell when but not really how, so let me add an answer also.
When
Any time you are writing production code that you are going to keep, you should have Unit Testing for it. The most helpful training that I saw on this was the following 2-part video series:
Understanding Test Driven Development (part 1)
Unit Testing Best Practices with Roy Osherove (part 2)
The first five minutes or so are just intro so you can skip to the end of that.
How
I am using Xcode 7 with Swift.
Start a new project and add a Unit Test.
I am calling mine MyProject. If you open the MyProjectTests group in the Project Navigator, you will see that Xcode has already created a Unit Test file for you called MyProjectTest.swift.
You can delete all the example methods for now and add a new func to test your own class method. Be sure to add the line #testable import MyProject at the top. If your project name has spaces in it then replace the spaces with underscores. (For example, "My Example Project" would use #testable import My_Example_Project.)
I am following the naming pattern of testMethodNameBeingTested_Senario_ExpectedBehavior. Unit Test names must begin with "test".
I will do something like this:
import XCTest
#testable import MyProject
class MyProjectTests: XCTestCase {
func testSum_TwoNumbers_ReturnsSum() {
// Arrange (set up the needed objects)
let myClass = MyClass()
// Act (run the method you want to test)
let sum = myClass.sum(1, 2)
// Assert (test that the behavior is as expected)
XCTAssertEqual(sum, 3)
}
}
Of course, the build fails because we haven't added the MyClass class yet.
Add your class.
I am adding a Swift file to MyProject called MyClass.
class MyClass {
func sum(a: Int, _ b: Int) -> Int {
return a + b
}
}
Press the test button next to the Test Unit Class or method to run the test again and it should pass.
To see it fail (an important part of Unit Testing) you could do something like return 0 in the sum method of MyClass. Then you would see the following when you run test:
You can go back and fix this and then add more Unit Tests. You can also make other Unit Test files for different classes if you like. Just right click the MyProjectTest group in the Project Navigator and choose "New File" Then choose Test Case Class.
Related
Xcode UI Test example
You should almost always unit test and you should write code with unit tests in mind.
The extremists write tests even before writing the code (it's called TDD - Test Driven Development).
I'll give you a real life example: I recently had to code a sorted NSArray that supports "intervals". Meaning, the array should know how to insert an interval and keep it sorted.
For example, the array would look like this: [1-3, 5-9, 12-50]. In this example there are 3 intervals in the array, and as you can see they are sorted.
After I wrote my class (I called it IntervalsArray), I HAD to write tests to make sure that it works correctly and that I will not "break" it if I or someone else make changes to the code in the future.
Here are some example tests (pseudo-code):
Test 1:
- Create a new IntervalsArray
- Insert a new interval to the array
- (TEST) make sure the array has 1 object in it
Test 2:
- Create a new IntervalsArray
- Insert 2 intervals into the array: [1-3] and [5-9]
- (TEST) make sure there are 2 items in the array
- (TEST) make sure interval [1-3] comes before interval [5-9]
At the end I had something like 15 tests to cover every aspect of my new array.
Here's a good unit-testing with Xcode tutorial.
You can also write logic tests (which are more complicated than unit tests) to test your UI. Read a little about UIAutomation, which is Apple's way of testing UI. It's not perfect, but it's pretty good. Here's an excellent tutorial about this.
If you consider yourself a good programmer, you should write unit-tests for your code.
Write unit tests any time you write code that you'll have to maintain. That is, if you ever want to refactor anything — changing the code but keeping the behavior. Which is pretty much every bit of production code.
The counterexample of "Hello, World" is not to bother with code you plan to throw away. A "spike solution" is just to figure out how you might approach a problem. Once you've figured it out, throw it away and start again. Only this time, you start with tests.
Calling TDD "extremist" makes it sound irrational and impractical. In fact, once you learn TDD, it saves time/money.
See Unit Testing Example with OCUnit for an example of how TDD works.
Any time your writing an application that has classes, that are not your own. That is a good time to add unit tests, to test those classes.
All but the most basic apps will have their own classes, so its almost always a good idea to unit test.
If you are creating libraries that other programmers will use, or that you will use in multiple projects, those should always have unit tests.
Unit tests save you a lot of time when things change, for instance, a new version of the OS comes out, it is much better to test with the unit tests then to just test the app.