Variable declaration inside of class in Swift - swift

I'm new in swift automated testing with XCTest framework.
In my work I faced with correct arrangement some parts of code inside of test
Please explain the difference between variable declaration in the beginning of the class and in the certain function. Which way is preferred?
Var.1
class someClass: XCTestCase {
let app = XCUIApplication()
func someFunc {
print (app.debugdescription)
}
}
Var. 2
class someClass: XCTestCase {
func someFunc {
let app = XCUIApplication()
print (app.debugdescription)
}
}

Var. 1 gives you the ability to configure your XCUIApplication in setup() and use it in the tests. Like this:
class someClass: XCTestCase {
var app: XCUIApplication!
func setUp {
app = XCUIApplication()
app.launchArguments.append("launchArgument")
setupSnapshot(app)
app.launch()
}
func test1 {
XCTAssertNotNil(app)
}
func test2 {
XCTAssertNotNil(app)
}
}
With Var. 2 you can setup your app differently in each test. Like this:
class someClass: XCTestCase {
func test1 {
let app = XCUIApplication()
app.launchArguments.append("withTestUser")
app.launch()
XCTAssertNotNil(app)
}
func test2 {
let app = XCUIApplication()
app.launchArguments.append("withNoData")
app.launch()
XCTAssertNotNil(app)
}
}

Both ways are possible but var 2 is preferred. For var 1 solution consider the following scenario:
class State {
var val: Int = 0
}
class TestClass: XCTestCase {
let state = State()
func test1() {
state.val = 5
XCTAssertEqual(5, state.val)
}
func test2() {
XCTAssertEqual(0, state.val)
}
}
This way result depends on which test will run first. If test2 will be the first then both tests will succeed. Other way, second test will fail.
For var 2 solution
class TestClass: XCTestCase {
func test1() {
let state = State()
state.val = 5
XCTAssertEqual(5, state.val)
}
func test2() {
let state = State()
XCTAssertEqual(0, state.val)
}
}
both tests succeeds no matter what test will run firstly. This makes var 2 solution preferred in most scenarios.
There is a case when var 1 is more convenient than var 2. It is when SUT have many dependencies and you have to copy and paste creation code for them in each test. Then you can declare dependencies as a class variables, but you must use test setUp (and possibly a tearDown) to ensure that their states is refreshed before each test
class TestClass: XCTestCase {
var dep1: Dependency1!
var dep2: Dependency2!
var sut: SUT!
func setUp() {
dep1 = Dependency1()
dep2 = Dependency2()
sut = SUT(dep1, dep2)
}
}

Variable declaration as Class level or the Function level is same as in other programming languages, so it would be great if you understand their basic principle.
Class level variable means that this variable can be accessed throughout the class, that means it can be used in any function of the same class. It also means that if you make the class as public, and that variable as public, then once the class is initialized it could be accessed within your program in other classes. Usually they could create memory issues if you don't manage them properly as they stay in the memory when the class itself is within the memory.
Function level variable can only be accessed within that specific function and not outside that function whether it's the same class or a different class, they have no reference outside their function. Usually they don't create memory issues in your whole program as these variables leave the memory when that function is completely executed.

Related

Shared instance accross inheritage

Say a framework provides customizable services through an open class A, that exposes a shared instance to use as follows:
open class A {
public static let shared = A()
open func aService() {}
}
The regular usage of the service is as follows:
A.shared.aService()
Important note: the shared instance itself is also used from within the class A code or related code in the Framework.
Say you want to customize the service through inheritance, and you still want to keep the use of the shared instanced as follows:
override class B: A {
public override func aService() {
super.aService()
}
}
When you refer to the shared instance, unfortunately, it refers to the class A instance where you would like it refers to the inherited class instance.
B.shared.aService() // Failed!: This actually calls A.shared.aService()
One way to fix it is to make the construct as follows:
class A {
public static var shared = A()
}
Then you are sure before any use of the service within you app, to change the instance as follows:
A.shared = B()
B.shared.aService() // OK! This actually calls B.aService()
Though the whole thing works, I would like to make it automatic and not rely on the initial line that changes the shared instance.
How would you do that?
[CODE FOR PLAYGROUND] that illustrates the goal to achieve and to help you better understand the question
open class A {
public static var shared = A()
open func aService() {
print("\(type(of: self)): service (from A)")
}
}
class B: A {
public override func aService() {
super.aService()
print("\(type(of: self)): service (from B)")
}
}
A.shared = B() // Question : How to remove the need to this line, yet achieving the same functionality (and output)
A.shared.aService()
B.shared.aService()
// The output (which is correct) :
//B: service (from A)
//B: service (from B)
//B: service (from A)
//B: service (from B)
There's a solution, but...
I do, personally, agree with the other comments here. This really doesn't sound like a job for the singleton pattern.
In your current solution, you seem perfectly happy to overwrite the singleton instance mid-execution, which means it's not a singleton. There's only ever supposed to be one instance of a singleton, and if you can continually create and assign a new instance to the shared variable without breaking anything, then it's just not necessary to have this global state across your application.
However, for the record, you can achieve what you want with a struct that composes the static instances of each class, and which can detect the calling context and return the appropriate one each time shared is accessed:
protocol ExampleProtocol {
static var shared: ExampleProtocol { get }
func service()
}
struct ExampleProvider {
private static var a = A()
private static var b = B()
static func instance(type: ExampleProtocol.Type) -> ExampleProtocol {
return type == A.self ? ExampleProvider.a : ExampleProvider.b
}
}
class A: ExampleProtocol {
static var shared: ExampleProtocol {
return ExampleProvider.instance(type: Self.self)
}
func service() {
print("Hello")
}
}
class B: A {
override func service() {
print("Goodbye")
}
}
A.shared.service() // Hello
B.shared.service() // Goodbye
So, yes, you can achieve what you want. But there's a pretty strong case for saying that you shouldn't...

Unable to cast to protocol from framework during test cases

So I have a class that comes from one of our internal frameworks. It is defined as follows:
// This lives within a framework
class ExternalClass: ExternalClassProtocol {
// implementation here
}
// This lives within my test target
class MockExternalClass: ExternalClassProtocol {
// Mock implementation here
}
// This lives within the same external frame work as ExternalClass
protocol ExternalClassProtocol: AnyObject {
// Protocol methods here
}
During my test cases, if I try to cast MockExternalClass as? ExternalClassProtocol, the test case crashes.
However, during live app runtime, there is no problem casting ExternalClass as? ExternalClassProtocol.
Is this an issue with trying to implement a protocol from an external module? Is there a way around this?
The class is being accessed through dependency injection (see below dependency injection implementation). The crash occurs on the resolve function.
If you actually debug to this point, you can see that the mock dependency IS in my dependency root (the services array below).
So I know its not failing to cast due to the dependency being missing.
#propertyWrapper
struct Injected<Value> {
var key: String
var wrappedValue: Value {
get { return Dependency.root.resolve(key: self.key) }
set { Dependency.root.add(key: self.key, newValue) }
}
init(key: String) {
self.key = key
}
}
class Dependency {
static let root = Dependency()
var services: [String : Any] = [:]
func add<T>(key: String, _ service: T) {
services[key] = service
}
func resolve<T>(key: String) -> T {
guard let component: T = services[key] as? T else {
// The test crashes here. It works fine on other mocks that are internal to the project
fatalError("Dependency '\(T.self)' not resolved!")
}
return component
}
func clearDependencies() {
self.services.removeAll()
}
private init() {}
}
In my test case:
#testable import MyProject
import ExternalDependency
class TestCase: XCTestCase {
private var subject: ClassWithService!
private var mockInternalClass: MockInternalClassProtocol!
private var mockExternalClass: MockInternallClassProtocol!
func setUp() {
mockExternalClass = MockExternalClass() // This one crashes when trying to cast to its parent protocol
mockInternalClass = MockInternalClass() // This one does not crash when casting to parent protocol.
Dependency.root.add(key: "internal_class", mockInternalClass)
Dependency.root.add(key: "external_class", mockExternalClass)
}
}
Some things I've tried:
Adding AnyObject to the protocol (this fixed a similar issue for internally defined classes that I mock).
changing mockExternalClass type to be the protocol
changing mockExternalClass type to be the implementation
Aside from one protocol being defined in one of our pods, there is no difference between the external protocol and the one we have defined in our own project.
One thing I have noticed is that the cast does not fail if you set a break point inside one of my test case functions. But if you try the same cast within the Dependency.resolve function it crashes. Which leads me to believe there is an issue with the generics.
Any ideas?

Testing multiple methods calling order

I have 3 methods that are related to a specific class which is defined as follows:
class MyClass: NSObject {
func myMethod() {
methodA()
methodB()
methodC()
}
func methodA() {}
func methodB() {}
func methodC() {}
}
I need to test that myMethod has called all 3 methods by the order they are implemented: methodA then methodB then methodC
to be tested with XCode Unit Tests, regardless of the implementation of these methods, I have created a subclass in the test case that looks like the following:
class ChildClass: MyClass {
var method1CallingDate: Date?
var method2CallingDate: Date?
var method3CallingDate: Date?
override func methodA() {
super.methodA()
method1CallingDate = Date()
}
override func methodB() {
super.methodB()
method2CallingDate = Date()
}
override func methodC() {
super.methodC()
method3CallingDate = Date()
}
}
Now in the test method, I start by calling those 3 methods, then I assert that all three dates are not nil first, then compare them like this:
XCTAssertLessThan(method1CallingDate, method2CallingDate)
XCTAssertLessThan(method2CallingDate, method3CallingDate)
The problem I ran into was that the test sometimes succeeds and sometimes fails, i guess due to Date object is (randomly) the same between 2 of the method calls.
Is there a better way to test the order of calling multiple methods ?
p.s. this is easily done in the Android SDK org.mockito.Mockito.inOrder
First, make a mock object that records the order. No dates, no strings. Just an enumeration.
class MockMyClass: MyClass {
enum invocation {
case methodA
case methodB
case methodC
}
private var invocations: [invocation] = []
override func methodA() {
invocations.append(.methodA)
}
override func methodB() {
invocations.append(.methodB)
}
override func methodC() {
invocations.append(.methodC)
}
func verify(expectedInvocations: [invocation], file: StaticString = #file, line: UInt = #line) {
if invocations != expectedInvocations {
XCTFail("Expected \(expectedInvocations), but got \(invocations)", file: file, line: line)
}
}
}
Then in the test:
mock.verify(expectedInvocations: [.methodA, .methodB, .methodC])
No async waiting. Simple to call. Clear failure messages.
You could do something like this using a String to keep track of the order:
class ChildClass: MyClass {
var order = ""
override func methodA() {
super.methodA()
order = String((order + "A").suffix(3))
}
override func methodB() {
super.methodB()
order = String((order + "B").suffix(3))
}
override func methodC() {
super.methodC()
order = String((order + "C").suffix(3))
}
}
Then, just check that order is "ABC".
Or, if it is valid to call B multiple times between A and C:
class ChildClass: MyClass {
var order = ""
override func methodA() {
super.methodA()
order = order.replacingOccurrences(of: "A", with: "") + "A"
}
override func methodB() {
super.methodB()
order = order.replacingOccurrences(of: "B", with: "") + "B"
}
override func methodC() {
super.methodC()
order = order.replacingOccurrences(of: "C", with: "") + "C"
}
}
Example:
let c = ChildClass()
c.methodA()
c.methodB()
c.methodB()
c.methodC()
print(c.order)
ABC
I've become a fan of using XCTestExpectation for this kind of thing. Here's an option.
class MyTestableClass: MyClass {
var methodAHandler: (() -> Void)?
// ...
override func methodA() {
methodAHandler?()
super.methodA()
}
And then in your test case
let expA = XCTestExpectation(description: "Method A Called")
let expB = ...
let expo = ...
objectUnderTest.methodAHandler = { expA.fulfill() }
/// ...
objectUnderTest.myMethod()
// ensure you use the enforceOrder param, which is optional
wait(for: [expA, expB, expC], timeout: 1.0, enforceOrder: true)
XCTestExpectation is made more for async testing, so the wait is slightly funny. But, it does do what you need, and would keep working even if eventually the internals of myMethod become asynchronous for some reason.
While I haven't used it myself, you also might want to check out Cuckoo. It's a mocking framework for Swift.
You're not asking the right question here. From a unit testing point of view you should not know/care that the tested method calls other methods, or even if other methods exist.
Unit tests should validate some observable result of the tested method. Anything that happens inside the tested method is irrelevant in the context of a unit test.
That's because unit tests should validate that the unit behaves as expected, i.e. they should validate against the specifications, not against the implementation.
Let's consider a simple example, unit testing a isPrime(n) function. Unless you're doing performance testing, you only care if the function returns the appropriate result for a couple of numbers. You don't care if the function checks all possible divisors, or if it uses a database of all known prime numbers, or if delegates the prime check to some 3rd party library/service.
The situation is not much different from yours. The fact that the three methods are called in a certain order needs to be validate via the external interface of the tested unit. For example if the three methods make API calls, then mock the API client and expect it to be requested three times, and with the expected URL/payload. If calling the three methods don't result in any noticeable changes, then there's not much you can test from the start, so again the fact that three methods are called in a certain order become irrelevant.
Unit testing is about validating the result of the execution of that unit, not anything more. Now, in an imperative programming language, the input->output functions are a minority, however this doesn't mean that we can't indirectly test if the function behaves as expected. You can use mocks, or validate some properties of the object after the function executes. Again, if there are no ways of externally checking the order of methods, then you have no specs to validate against.

swift singleton with parameters

I'm relatively new to swift and searched around but could not find any satisfactory answer to my problem. I would like to have a Singleton class instance which can be initialized with some variables. E.g.
public class Singleton {
var car: String
var bus: String
init(car: String, bus: String) {
self.car = car
self.car = bus
}
func drive() {
print("I will drive")
}
}
public class SingletonConsumer {
// create an instance of Singleton Once
var driver: Singleton = Singleton(car: "honda", bus: "volvo")
driver.drive()
}
public class driverClassWorld : SingletonConsumer {
driver.drive()
}
how can i achieve it? I tried protocol but issue i am hitting is how to instantiate singleton class with parameters.
I don't get this problem?
First remove singleton from your brain for a moment. Because I think you have the wrong idea on what a singleton is.
Now lets rephrase your question to: "How to instantiate a class with parameter"
Its like this:
import Foundation
class Test {
let someText : String!
init(something:String){
someText = something
}
func test(){
print("TEST \(someText)")
}
}
let a = Test(something: "Me")
a.test()
Output:
TEST Optional("Me")
You just need to define a init with the parameters you want.
Now to properly instantiate a singleton (basically it just the class above but single instance). There are a lot of ways, the old Objective C approach is still valid.
But for swift this is the most common pattern. You need to define a Static Property.
Example:
import Foundation
class Test {
static let shared = Test(something: "REAL SINGLETON")
let someText : String!
init(something:String){
someText = something
}
func test(){
print("TEST \(someText)")
}
}
Test.shared.test()
Output:
TEST Optional("REAL SINGLETON")
Now reread the definition of a singleton:
a singleton class is a class that can have only one object (an
instance of the class) at a time
For other patterns in declaring a singleton:
https://cocoacasts.com/what-is-a-singleton-and-how-to-create-one-in-swift
Now, you might wonder: When does this singleton instance instantiated?
Answer: It is when it is first used/called.

My first swift hello world application, build error when trying access a class

So this is my hello world application with swift. Also not used to XCode. So, might be a silly mistake here.
I just have one class Deck.swift
class Deck {
let decks : Integer = 0
init () {
decks = 1
}
init (amountOfDecks : Integer){
decks = amountOfDecks
}
func getAmountOfCards() -> Integer {
return 0
}
}
Then I'm trying to run a unit test that look like this
import XCTest
import helloWorldv2
class helloWorldv2Tests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testDeckConstructor() {
var deck = Deck(amountOfDecks: 2)
XCTAssert(true, "Pass")
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
}
If I comment out the line var deck = Deck(amountOfDecks: 2) then it builds fine. If that line is included I get build failed.
Anyone know what I'm doing wrong here?
If you want to modify deck param you have to declare it like this
var decks : Int = 0
If you put let your variable is read only after first assignment.
Whilst #jaumard is correct in saying that it is var rather than let that you should be using, you should use "Int" as the type, not "Integer" (which is a protocol, not a type). You get away with it because both are superfluous because of type inference...
var decks = 0
is quite sufficient, or
var decks: Int = 0
if you want to be verbose.
See this answer.
No need to turn your let constant into a var.
Simply don't provide a default value when declaring it.
let decks : Int
Your = 0 already initializes your constant, and than you're trying to change it in init, which is not allowed for constants.