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

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

Related

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

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

Swift: overriding an initializer that takes an NSInvocation

I'm trying to create a reusable test harness in Swift with the idea that subclasses will extend the test harness to provide the instance under test, and can add their own subclass-specific test methods, something like this:
class FooTestHarness: XCTestCase {
let instance: Foo
init(instance: Foo) {
self.instance = instance
}
func testFooBehavior() {
XCTAssert(instance.doesFoo())
}
}
class FooPrime: Foo {
func doesFooPrime(): Bool { /* ... */ }
}
class FooPrimeTests: XCTestCase {
init() {
super.init(FooPrime())
}
func myInstance(): FooPrime {
return instance as FooPrime
}
func testFooPrimeBehavior() {
XCTAssert(myInstance().doesFooPrime())
}
}
However, when XCode's testrunner tries to run FooPrimeTests, it doesn't call the no-arg init(), it calls init(invocation: NSInvocation!) (and fails because there isn't one). I tried to override this in FooTestHarness:
init(invocation: NSInvocation!, instance: Foo) {
self.instance = instance
super.init(invocation)
}
and in FooPrimeTests:
init(invocation: NSInvocation!) {
super.init(invocation, FooPrime())
}
but this fails with the message 'NSInvocation' is unavailable.
Is there a workaround?
I'm not os sure if I got it right, but checking the code you suggested you should get a compiler Error like:
Which actually I reckon is quite normal since your FooPrimeTests is just subclassing XCTestCase which has got different init like:
init!(invocation: NSInvocation!)
init!(selector: Selector)
init()
Probably when you posted you're question you're running on an older version of Swift, (I'm currently running it on the Xcode Beta 6.2) that's why you can't see the error. But, and I say again if I got your point right, your class FooPrimeTests can't see you custom initializer just because is sublcassing XCTestCase, rather then FooTestHarness. Which is the class where the init(instance: Foo) is defined.
So you might probably want to define FooPrimeTests as subclass of FooTestHarness. That way you should be able to correctly see your initializer. Hope this help.

Access variable in different class - Swift

i got two swift files :
main.swift and view.swift
In main.swift i have a variable (Int) initially set to 0.
With an IBACtion I set that variable to be 10, and everything is ok.
However, if I try access that variable from view.swift, with a simple call like main().getValue(), i get always 0 and not 10 even if the variable has changed it's value in main.swift.
The method getValue() in main.swift looks like this:
func getValue() -> Int {
return variable
}
EDIT
Here is the code (Translated from Italian :D )
import Cocoa
class Main: NSObject {
var variable: Int = 0
func getValue() -> Int {
return variable
}
#IBAction func updateVar(sender: AnyObject!) {
variable = 10
}
}
class View: NSView {
override func drawRect(dirtyRect: NSRect) {
println(Main().getValue()) //Returns always 0
}
}
Thanks in advance
Alberto
I have solved this by creating a generic main class which is accessible to all views. Create an empty swift file, name it 'global.swift' and include it in your project:
global.swift:
class Main {
var name:String
init(name:String) {
self.name = name
}
}
var mainInstance = Main(name:"My Global Class")
You can now access this mainInstance from all your view controllers and the name will always be "My Global Class". Example from a viewController:
viewController:
override func viewDidLoad() {
super.viewDidLoad()
println("global class is " + mainInstance.name)
}
There is an important distinction to be made between "files" in Swift and "classes". Files do not have anything to do with classes. You can define 1000 classes in one file or 1 class in 1000 files (using extensions). Data is held in instances of classes, not in files themselves.
So now to the problem. By calling Main() you are creating a completely new instance of the Main class that has nothing to do with the instance that you have hooked up to your Xib file. That is why the value comes out as the default.
What you need to do, is find a way to get a reference to the same instance as the one in your Xib. Without knowing more of the architecture of your app, it is hard for me to make a suggestion as to do that.
One thought, is that you can add a reference to your Main instance in your Xib using an IBOutlet in your View. Then you can simply do self.main.getValue() and it will be called on the correct instance.