I am writing unit tests for my Swift application and I would like to delete the app in between each test case for certain suites. I already have a script action set up that uninstalls the app before the whole suite runs. But I have not found a way to be able to delete the app off the simulator in between each test invocation. Is there a way to do this?
What I want is:
import XCTest
#testable import My_App
class MyTests: XCTestCase {
override func setUpWithError throws () {
magic("xcrun simctl uninstall booted ${PRODUCT_BUNDLE_IDENTIFIER}")
}
func testTheThings() {
// test runs with a completely fresh slate...
}
}
Please note that this is unit testing and not UI testing - so I don't think I can have the test delete the app from the Springboard, which is what I otherwise do in my UI tests to give each test a clean slate.
Related
I created the new Multiplatform app with Xcode called Tester and then added a super simple class:
class Transaction {
var time = "1"
}
In the Tests_iOS I have this:
import XCTest
#testable import Tester
class Tests_iOS: XCTestCase {
func testExample() throws {
let t = Transaction()
XCTAssertEqual(t.time, "1")
}
}
The app compiles, however when I try to run the tests, compilation fails with this error:
Undefined symbols for architecture arm64:
"type metadata accessor for Tester.Transaction", referenced from:
Tests_iOS.Tests_iOS.testExample() throws -> () in Tests_iOS.o
"Tester.Transaction.__allocating_init() -> Tester.Transaction", referenced from:
Tests_iOS.Tests_iOS.testExample() throws -> () in Tests_iOS.o
ld: symbol(s) not found for architecture arm64
What am I doing wrong? This is on an M1 Mac using Xcode 13.3
The problem is most likely that you have added your test to the test target that gets automatically created when you create a new multi-platform project and that target is a UI test target and not an ordinary unit test target.
For those tests you do not access the public api of your app like your Transaction class but instead UI components so the test framework has no access to the Transaction class.
The solution is to create a new unit test target, File -> New -> Target... and select Unit Test (remember to select the correct platform because this needs to be done separately for each supported platform).
Once done, move your test to the new target or copy it to the test file that is generated and your test will build and run.
I am having a separate integration test file for each screen and I want to run all the integration tests with a single command like “flutter tests”. I looked into the doc but was not able to find any way to do this. This also causes an issue with the firebase test lab apk. To create an android test apk I can only specify a single test file path to create the apk.
// flutter build generates files in android/ for building the app
flutter build apk
./gradlew app:assembleAndroidTest
./gradlew app:assembleDebug -Ptarget=integration_test/whattodo_tests.dart
For now, I found two workarounds for this.
I’ve moved all my tests to a single dart file with a group test.
But this workaround does not scale well. For the 5-10 test it’s working fine. But let say if we have 50-75 test then it will be a mess to navigate and understand tests in single file.
Create a script to run all tests one by one. This might work on our own CI pipeline, but this won't work in the firebase test lab.
Does anyone able to solve this issue or any better solution?
I have came across one project on GitHub has this kind of structure, I think which may help..
Make common file and import different files, folders or modules on that common file for testing
main.dart
import 'package:integration_test/integration_test.dart';
import 'about_us_page_test.dart' as about;
import 'add_label_page_test.dart' as label;
import 'add_project_page_test.dart' as project;
import 'add_task_page_test.dart' as tasks;
import 'completed_tasks_page_test.dart' as tasks_completed;
import 'home_page_test.dart' as home;
import 'whattodo_tests.dart' as whattodo;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
whattodo.main();
home.main();
tasks.main();
tasks_completed.main();
project.main();
label.main();
about.main();
}
to run all these tests
flutter drive \
--driver=test_driver/integration_test_driver.dart \
--target=integration_test/main.dart
There is now a better way of doing it. Just use the test command like this.
To run all test
flutter test integration_test
To run a specific test
flutter test integration_test/app_test.dart
Reference.
I am trying to write an extension for the XCTest framework in Swift. In order to do so, I created a project with two targets: the main/production target and a test target.
As I am writing an extension for XCTest, I need to import XCTest within my main/production target as well. However, I am having trouble to do so. When in Xcode and I click on my project, then select the main target, go to Build Phases, Link Binary With Libraries and add XCTest there, I get a compile error:
ld: framework not found XCTest
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I also tried the solution provided here which unfortunately doesn't work either.
Auxiliary information on XCTest itself is sparse and hard to find, I was also chasing down the same functionality and finally managed to get it working.
I am on XCode 10.1 and running on a real iPhone with iOS 11. I am certain the general technique will work for other versions, but probably will require a few tweaks.
The general steps are described in this stackoverflow answer, but required several additional steps and tweaks to work for me on a real iPhone:
Is it possible to run XCTest tests in an iOS app?
Follow the steps in the above link. The below steps are deviations from those instructions that were required for me.
Copy in the XCTest framework as described in the above link. NOTE: Use the framework for the iPhone.OS platform and not the simulator as it describes. You can find this framework file inside the actual XCode Application package on your mac. (Right click, "Show Package Contents", then look in ./Contents/Developer/Platforms/iPhoneOS.platform
Disable bitcode in your app target. This solves a linker error. Here is an example of enabling it: how to ENABLE_BITCODE in xcode 7?
When dragging the XCTest.framework file to the linked binaries in your target, ensure that you also drag it to the "Embedded Binaries" which is directly above the "Linked Frameworks and Libraries" option. If you don't do this you will get a runtime error.
The ViewController code to start the tests is slightly different in new Swift, here is what I am using:
import UIKit
import XCTest
class ViewController: UIViewController {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("running tests!")
let suite = XCTestSuite.default;
for test in suite.tests {
test.run()
}
}
}
That should be it! When I run the above app, then touch the screen, all of the tests from my UITesting target run flawlessly and pass!
I'm currently trying to write unit tests (NOT UI Tests) for my (macOS) Xcode project. I have created a new Unit Test target which creates a blank unit test file for me.
This complies and links fine, but there are no tests.
As soon as I add the line #testable import Pilot, where Pilot is the name of my App Target, and I try to compile and run, it fails with this message:
Linker command failed with exit code 1 (use -v to see invocation)
I've tried everything I can find, but nothing seems to be working. The other posts I have read on here deal with this problem in UI Tests, but that is because you cannot use #testable in UI Tests. You are supposed to be able to use it in Unit Tests, but I can't figure out why this is not working.
Does anyone have any insight?
If it helps, my project is located at: https://github.com/RohanNagar/pilot-osx
Here is the full PilotTests.swift file:
import XCTest
#testable import Pilot
class PilotTests: 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.
}
}
}
If your CocoaPods frameworks not included in the Test targets. It will throw this error.
I made sure running a pod install, but still it failed.
So 'pod deintegrate Yourproject.xcodeproj' and reinstall (pod install), clears the issue.
The import fails because the project fails to link together. I downloaded it and I get the following error trying to run it:
Showing Recent Issues
ld: framework not found Realm for architecture x86_64
Try to clean your build folder, or download the project to a new folder, and fix this issue... after that you'll be able to compile and #testable import Pilot.
Set Host Application to your Project Target.
Also, check the Allow testing Host Application APIs is turned on.
Select your test target
Select Build Phases
In the Framework Search Paths, add this
"${PODS_CONFIGURATION_BUILD_DIR}/" with recursive option
I have a new Swift project I started on and the first thing I did was create my podfile and bring in two cocoapods.
target 'Life Stream' do
pod 'SSKeychain'
pod 'LiveSDK'
end
target 'Life StreamTests' do
pod 'SSKeychain'
pod 'LiveSDK'
end
I then ran pod setup to ensure my cocoapods were installed, then ran pod install to install my pods. The new workspace project was created and I opened Xcode in it. Everything builds.
I then added my bridge header, and started using the SSKeychain pod. Things continued to build.
Bridge:
#ifndef Lifestream_Bridging_Header_h
#define Lifestream_Bridging_Header_h
#import "AFNetworking/AFNetworking.h"
#import "SSKeyChain.h"
#import "LiveConnectClient.h"
#endif /* Lifestream_Bridging_Header_h */
class UserService {
init() {
SSKeychain.setPassword("test", forService: "service", account: "blah")
}
}
I then try to use the LiveSDK
class HttpOperation : NSOperation, LiveAuthDelegate {
let baseUl = NSURL(string: "https://api.onedrive.com/v1.0")
override func main() {
let client = LiveConnectClient(clientId: "000000004C1549C8", delegate: self)
}
func authCompleted(status: LiveConnectSessionStatus, session: LiveConnectSession!, userState: AnyObject!) {
}
}
The project built a couple of times, but now it no longer builds. I've not changed a line of code (CMD+tabbed to Safari for research). It doesn't matter if I clean the project, rebuild, or delete all of my pods and reinstall them, I can't get the project to build.
The compiler error I receive
Command failed due to signal: Segmentation fault: 11
I've seen people say this can be caused by the compiler not being able to find linked stuff. I then looked and noticed that my /frameworks folder contains all of the .a files in red (linked files?)
I assume that's because the files are missing, but why would that be? If I installed the pods via cocoapods and they were building fine, why now would those files go missing and the build stop (if that is the cause)?
I've been trouble shooting this for the last few hours and have not been able to figure it out. Any help would be appreciated.
My full compiler error log dump can be found on github
Edit
There are additional build errors associated with the unit test project, but I assume those are due to the project the unit tests depend on not building.
Use of undeclared type 'LiveAuthDelegate'
Use of undeclared type 'LiveConnectSessionStatus'
Use of undeclared type 'LiveConnectSession'
Use of unresolved identifier 'LiveConnectClient'
These errors point to the NSOperation subclass I show above. I'm not sure if that helps or not.