Inherit tests from a common XCTestCase from a Swift package - swift

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)?

Related

Swift Package Module name conflicting with struct, class or any type defined in other Modules

created Swift Package Module with name OSLogBoolFormat and then I have to import os in the code. when I try to access types defined in OSLogBoolFormat module it's not being recognized and its only pointing to os.OSLogBoolFormat.
import UIKit;
import os;
import OSLogBoolFormat;
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let name = OSLogBoolFormat.PrcoessKT.name
print(name)
}
}
OSLogBoolFormat package is conflicting with OSLogBoolFormat enum defined in os Module.
Code Example: https://github.com/sreexamus/NewOneTest

Swift Error - Method Does not override any method from its superclass

I am running into an issue where when I am attempting to override a function it is telling me that there is no method in the superclass. The subclass is in an XCTest. When I subclass in the regular project it works perfectly but the XCTest does not work for some reason Below is the Code
SuperClass
class BackupServerCell: UITableViewCell {
#IBOutlet var serverNameLabel: UILabel!
#IBOutlet var serverDescriptionLabel: UILabel!
func configCell(with server: VeeamBackupServer) {
}
}
Subclass - Located in the XCTest file
class MockBackupServerCell : BackupServerCell {
var configCellGotCalled = false
override func configCell(with server: VeeamBackupServer) {
configCellGotCalled = true
}
}
When you are working on a Test target, its sometime needed to import your main project.
Let's say your project is named 'MyAwesomeProject', just need to add this line in your test file:
#testable import MyAwesomeProject
To obtain something like this:
import XCTest
#testable import MyAwesomeProject
class TestStaticQueries: XCTestCase {
// Add your test methods here.
}
#DDelforge, was partially correct. I had to add the BackupServerCell class, to the Test Target. Not sure why this class is different, but hey, it works.
Thank you all

Is it possible to hide classes from ui tests

I have a few helper classes like UnlockedTestCase that configure my app for special scenario tests.
Theses classes show up in the test navigator without tests.
Is there a way to mark then as "not test classes" in order for them to be ignored by the test navigator?
UPDATE: Sample code:
class UnlockedTestCase: XCTestCase {
var app = XCUIApplication()
override func setUp() {
super.setUp()
continueAfterFailure = false
app.launchArguments = ["uiTesting", "unlock"]
app.launch()
}
}
A test would then be written as:
class UnlockedUITests: UnlockedTestCase {
func testButton() {
XCTAssers(app.buttons["SomeButtonInTheUnlockedState"].exists)
}
}
No, there is not a way to exclude that kind of class from the test navigator without losing the ease of defining the setUp(), as the way that it discovers test case classes is simplistic, and from the point of view of the navigator, you could add test cases to the parent/helper class at any moment since it is an XCTestCase descendant.
There is no protocol for 'helper' or 'abstract-only' classes which support inheritance in the way that you require, since inheritance from XCTestCase is required for the automatic discovery and usage of tests and test hooks like setUp().
If you really want to get rid of your helper entities from the test navigator, you could abstract them into protocols with extensions where Self: XCTestCase (to allow you access to XCTestCase's interface in the extension), have your test class conform to them, and override setUp() in the class where your tests are.
protocol UnlockableTest {}
extension UnlockableTest where Self: XCTestCase {
func unlockSetUp() {
continueAfterFailure = false
app.launchArguments = ["uiTesting", "unlock"]
app.launch()
}
}
class UnlockedUITests: XCTestCase, UnlockableTest {
var app = XCUIApplication()
override func setUp() {
super.setUp()
unlockSetUp()
}
func testButton() {
XCTAssert(app.buttons["SomeButtonInTheUnlockedState"].exists)
}
}
However, I think the simplicity and convenience of your current approach is the preferable compromise. Protocols also can't contain stored properties though, so in order to get the benefit of a stored property, you'd need to add the app property to every XCTestCase descendant too.
You can do this with Swift packages now, if your tests are in a Swift Package then you can have a helper module that contains your base classes and these will not be added to the sidebar as empty test cases.
You can mix an xcodeproj with a local to the source folder swift package to facilitate this, and in general I would personally recommend this as it improves build times and allows you to make your codebase more modular with granular access control.
Assuming the following structure:
MyTestHelperClassName: XCTestCase {
//... your helper methods
}
Remove its subclass declaration of XCTestCase
i.e the : XCTestCase part
Then it will not appear in the "Test Navigator"

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