Mac Command Line Tool Swift Unit Tests - swift

I want to unit test a command line tool.
I go through the following progress
Create a new project using the macOS > Command Line Tool template. Call it "MyProject"
import Foundation
class MyCode {
func hello() {
print("hello")
}
}
let code = MyCode()
code.hello()
Choose File > New > Target.
Select the macOS Unit Testing Bundle template. Call it "MyTests"
import XCTest
#testable import MyProject
class MyTests: XCTestCase {
func testCode() {
let sol = MyCode()
sol.hello()
}
}
Switch to test target.
Build failed.
How can I test this?

Related

Swift error "Hashbang line is allowed only in the main file"

I wish to create an interpreted Swift command-line utility. Thus, in Xcode 13.1, I create a new project, and use the template "Command Line Tool". This results in an empty project with a single file, called main.swift.
I want to distribute this command-line utility as a single file, so having the "main.swift" name isn't useful. I rename it to MyCommandlineProject.swift, then add the hashbang line on top, and add code that marks it as being the main file. The contents now look as follows:
#!/usr/bin/swift
import Foundation
#main
struct CLI {
static func main() {
print("Hello, World!")
}
}
Despite the #main annotation, I still get the following compiler error:
Hashbang line is allowed only in the main file
Why?
If you are just writing a script you don't need any of that #main stuff. #main is really only for when you have multiple files that you need to compile into an executable.
For a script, like you are writing, you can just add top level functions and they will get called just as if you were writing in a playground.
#!/usr/bin/swift
import Foundation
print("Hello, World!")
You can execute the script with:
chmod 744 scriptName.swift
./scriptName.swift
Or
swift scriptName.swift
Now if you have multiple files, let's call them First.swift:
import Foundation
#main enum First {
static func main() {
print("First.main")
Second.execute()
}
}
And Second.swift:
import Foundation
enum Second {
static func execute() { print("Second.execute") }
}
You have to prefix your entry point with #main like we did for First. You also have to give it a static main() method.
First you have to compile:
swiftc -o awesome First.swift Second.swift
Then to run:
./awesome

Inherit tests from a common XCTestCase from a Swift package

Consider the following:
A Swift package Feature has a protocol Component and a couple of implementations FooComponent, BarComponent, etc.
The package has its own tests FeatureTests and the Component's are tested in a way, that individual implementations inherit a single test case in order to test the common expectations of a Component:
import XCTest
#testable import Feature
class ComponentTests: XCTestCase {
var sut: Component!
override class var defaultTestSuite: XCTestSuite {
XCTestSuite(name: "EventStorageService Interface Tests Excluded")
}
func test_common() { }
}
...
class FooComponentTests: ComponentTests {
override func setUpWithError() throws {
try super.setUpWithError()
sut = FooComponent()
}
override class var defaultTestSuite: XCTestSuite {
XCTestSuite(forTestCaseClass: Self.self)
}
func test_specific() { }
}
class BarComponentTests: ComponentTests {
override func setUpWithError() throws {
try super.setUpWithError()
sut = BarComponent()
}
...
This all works really nicely within the Swift package.
Now let's consider the app App injects its own custom Component implementation and also wants to test it and benefit from the already written common tests.
import XCTest
#testable import App
#testable import Feature
class CustomComponentTests: ComponentTests { // Error: Cannot find type 'ComponentTests' in scope
...
Of course the above does not work as the compiler does not find ComponentTests. And importing FeatureTests also fails.
import XCTest
#testable import App
#testable import FeatureTests // Error: No such module 'FeatureTests'
class CustomComponentTests: ComponentTests {
...
Does anyone have an idea how to achieve the desired outcome (i.e. inherit common tests for the protocol defined within the lib in order to not duplicate the test code)?

Issue with swift framework import

I have created a swift framework.
In this framework i have some swift file and one category in objective-C (so there is the .h and .m files).
I successfully build my framework, but when i import it into another project, only the method from my category (written in objective-C) are visible. If i try to use any swift class i got an error "Use of unresolved identifier".
I have checked the following points in my framework project :
all my swift class are public public class Toto
i have set the build settings - packaging - defines module param to yes
In my project where the framework is imported, i have the following code :
import UIKit
import myframework
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
toto()
}
func toto() {
let data = NSData()
data.isGzippedData()
var client = Client ()
NSLog("ok");
}
}
I have an error "Use of undeclared identifier" for the line var toto = Client (), but in my swift framework the class Client is public and its default constructor is public.
However, if i comment this line, the code works fine, even if the method isGzippedData is declared and implement in my framework (but in objective-C).
How can i use the swift class from my framework into my project ?

Unable to access Main Target Methods when Adding Tests to OSX Project in Swift

I have tried adding a testing bundle to my Project which seems to have succeeded.
However when I try to create instances of the Classes in my main project- I am unable to see them.
The Project seems to build fine - but I can' instantiate any of the test objects
Any ideas how to access them
Example Class to Test:
class EmailHelper: NSObject {
func generateEmailBody (greeting: String, bodyContent: String) -> String {
//Content goes in here
return message
}
}
import XCTest
class MyProject_DesktopTests: 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() {
// The Test would go in here but I can't seem to resolve EmailHelper class- it generates a lint error
// 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.measureBlock {
// Put the code you want to measure the time of here.
}
}
}
I managed to get it working by adding Testable to the top of the class( This appears to be OSX specific issue)
import XCTest
#testable import MyProjectName // <--- This was the missing bit.... :)
class MyProject_DesktopTests: 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() {
// The Test would go in here but I can't seem to resolve EmailHelper class- it generates a lint error
// 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.measureBlock {
// Put the code you want to measure the time of here.
}
}
}
Also be sure to clean your project after adding it an it seems to work.

Xcode UI test - swipeRight() not working after tearDown

I have a logout function that gets called during every tearDown(), but does not work when called this way. If I call the same logout function during the test, it works fine. I'm wondering what are the behaviors of XCUI testing during teardown, are there limitations? I tried debugging and calling app.swipeRight() using the lldb (espression->write code)...
-------
Navbar.swift
-------
import XCTest
import Foundation
class NavbarTest: XCTestCaseLib{
override func setUp()
{
super.setUp()
continueAfterFailure = false
}
override func tearDown()
{
logout()
super.tearDown()
}
func testSideBar_STAGING(){
//...<test code that executes no problem>
//...
}
}
-----
XCTestCaseLib.swift
------
import XCTest
import Foundation
class XCTestCaseLib: XCTestCase {
let app = XCUIApplication()
func logout() {
app.swipeRight()
...
}
From the code you've posted, it appears to be your imports (I'm assuming here that these classes are in different files, otherwise your inheritance is ambiguous). If I'm mistaken please update your question to include your file structure. Play around with your imports and inheritance.
I believe you just need to import XCTest on your NavbarTest class