How to define global final variable that not changes for all tests under class? - swift

I write unit test in Swift.
I call my app method and through delegate get back JSON object that represents request.
Now I want to validate all fields of JSON. Each validation should be in separate test.
This is what I wrote:
class LaunchTests: XCTestCase, TestServerHandlerDelegate {
var theExpectation:XCTestExpectation?
var launchRequest:String? = nil
public func onSend(_ data: Data!) {
launchRequest = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
theExpectation?.fulfill()
}
override func setUp() {
super.setUp()
// we wait in setUp till get 'launchRequest'
if launchRequest == nil {
theExpectation = expectation(description: "initialized")
MyApp.shared().setDelegate(self)
MyApp.shared().launch()
// Loop until the expectation is fulfilled in onDone method
waitForExpectations(timeout: 500, handler: { error in XCTAssertNil(error, "Oh, we got timeout")})
}
}
override func tearDown() {
super.tearDown()
}
func test___01_platform(){
if let _ = fetchJsonValue(key: "somekey", value: launchRequest){
//...
}
}
func test___02_platform(){
if let _ = fetchJsonValue(key: "platform", value: launchRequest){
//...
}
}
The problem is: for each run launchRequest is nil. I know that its right behavior but I want to call MyApp.shared().launch() once only and run multiple tests for launchRequest data.
How can I achieve it?
(I know its not good practice for unit testing but anyways)
Thanks,

Well, if you really want that, you can just put launchRequest outside of your LaunchTests class:
var launchRequest:String? = nil
class LaunchTests: XCTestCase, TestServerHandlerDelegate {
...
}

The solution was to define launchRequest as static (as Maxim Shoustin mentioned):
static var launchRequest:String? = nil
In this case everything works as expected

Related

Swift 5.5 test async Task in init

I would like to test if my init function works as expected. There is an async call in the init within a Task {} block. How can I make my test wait for the result of the Task block?
class ViewModel: ObservableObject {
#Published private(set) var result: [Item]
init(fetching: RemoteFetching) {
self.result = []
Task {
do {
let result = try await fetching.fetch()
self.result = result // <- need to do something with #MainActor?
} catch {
print(error)
}
}
}
}
Test:
func testFetching() async {
let items = [Item(), Item()]
let fakeFetching = FakeFetching(returnValue: items)
let vm = ViewModel(fetching: FakeFetching())
XCTAssertEqual(vm.result, [])
// wait for fetching, but how?
XCTAssertEqual(vm.result, items])
}
I tried this, but setting the items, only happens after the XCTWaiter. The compiler warns that XCTWaiter cannot be called with await, because it isn't async.
func testFetching() async {
let items = [Item(), Item()]
let fakeFetching = FakeFetching(returnValue: items)
let expectation = XCTestExpectation()
let vm = ViewModel(fetching: FakeFetching())
XCTAssertEqual(vm.result, [])
vm.$items
.dropFirst()
.sink { value in
XCTAssertEqual(value, items)
expectation.fulfill()
}
.store(in: &cancellables)
let result = await XCTWaiter.wait(for: [expectation], timeout: 1)
XCTAssertEqual(result, .completed)
}
Expectation-and-wait is correct. You're just using it wrong.
You are way overthinking this. You don't need an async test method. You don't need to call fulfill yourself. You don't need a Combine chain. Simply use a predicate expectation to wait until vm.result is set.
Basically the rule is this: Testing an async method requires an async test method. But testing the asynchronous "result" of a method that happens to make an asynchronous call, like your init method, simply requires good old-fashioned expectation-and-wait test.
I'll give an example. Here's a reduced version of your code; the structure is essentially the same as what you're doing:
protocol Fetching {
func fetch() async -> String
}
class MyClass {
var result = ""
init(fetcher: Fetching) {
Task {
self.result = await fetcher.fetch()
}
}
}
Okay then, here's how to test it:
final class MockFetcher: Fetching {
func fetch() async -> String { "howdy" }
}
final class MyLibraryTests: XCTestCase {
let fetcher = MockFetcher()
func testMyClassInit() {
let subject = MyClass(fetcher: fetcher)
let expectation = XCTNSPredicateExpectation(
predicate: NSPredicate(block: { _, _ in
subject.result == "howdy"
}), object: nil
)
wait(for: [expectation], timeout: 2)
}
}
Extra for experts: A Bool predicate expectation is such a common thing to use, that it will be found useful to have on hand a convenience method that combines the expectation, the predicate, and the wait into a single package:
extension XCTestCase {
func wait(
_ condition: #escaping #autoclosure () -> (Bool),
timeout: TimeInterval = 10)
{
wait(for: [XCTNSPredicateExpectation(
predicate: NSPredicate(block: { _, _ in condition() }), object: nil
)], timeout: timeout)
}
}
The outcome is that, for example, the above test code can be reduced to this:
func testMyClassInit() {
let subject = MyClass(fetcher: fetcher)
wait(subject.result == "howdy")
}
Convenient indeed. In my own code, I often add an explicit assert, even when it is completely redundant, just to make it perfectly clear what I'm claiming my code does:
func testMyClassInit() {
let subject = MyClass(fetcher: fetcher)
wait(subject.result == "howdy")
XCTAssertEqual(subject.result, "howdy") // redundant but nice
}
Tnx to matt this is the correct way. No need for async in the test function and just using a predicate did the job.
func testFetching() {
let items = [Item(), Item()]
let fakeFetching = FakeFetching(returnValue: items)
let expectation = XCTestExpectation()
let vm = ViewModel(fetching: FakeFetching())
let pred = NSPredicate { _, _ in
vm.items == items
}
let expectation = XCTNSPredicateExpectation(predicate: pred, object: vm)
wait(for: [expectation], timeout: 1)
}
Slight variation on Matt's excellent answer. In my case, I've broken out his extension method into even more granular extensions for additional convenience.
Helper Framework
public typealias Predicate = () -> Bool
public extension NSPredicate {
convenience init(predicate: #escaping #autoclosure Predicate) {
self.init{ _, _ in predicate() }
}
}
public extension XCTNSPredicateExpectation {
convenience init(predicate: #escaping #autoclosure Predicate, object: Any) {
self.init(predicate: NSPredicate(predicate: predicate()), object: object)
}
convenience init(predicate: #escaping #autoclosure Predicate) {
self.init(predicate: NSPredicate(predicate: predicate()))
}
convenience init(predicate: NSPredicate) {
self.init(predicate: predicate, object: nil)
}
}
public extension XCTestCase {
func XCTWait(for condition: #escaping #autoclosure Predicate, timeout: TimeInterval = 10) {
let expectation = XCTNSPredicateExpectation(predicate: condition())
wait(for: [expectation], timeout: timeout)
}
}
With the above in place, the OP's code can be reduced to this...
Unit Test
func testFetching() {
let items = [Item(), Item()]
let fakeFetching = FakeFetching(returnValue: items)
let vm = ViewModel(fetching: FakeFetching())
XCTWait(for: vm.items == items, timeout: 1)
}
Notes on Naming
Above, I'm using a somewhat controversial name in calling my function XCTWait. This is because the XCT prefix should be considered reserved for Apple's XCTest framework. However, the decision to name it this way stems from the desire to improve its discoverability. By naming it as such, when a developer types XCT In their code editor, XCTWait is now presented as one of the offered auto-complete entries** making finding and using much more likely.
However, some purists may frown on this approach, citing if Apple ever added something named similar, this code may suddenly break/stop working (although unlikely unless the signatures also matched.)
As such, use such namings at your own discretion. Alternately, simply rename it to something you prefer/that meets your own naming standards.
(** Provided it is in the same project or in a library/package they've imported somewhere above)

How to test a method that contains Task Async/await in swift

Given the following method that contains a Task.
self.interactor is mocked.
func submitButtonPressed() {
Task {
await self.interactor?.fetchSections()
}
}
How can I write a test to verify that the fetchSections() was called from that method?!
My first thought was to use expectations and wait until it is fulfilled (in mock's code).
But is there any better way with the new async/await?
Ideally, as you imply, your interactor would be declared using a protocol so that you can substitute a mock for test purposes. You then consult the mock object to confirm that the desired method was called. In this way you properly confine the scope of the system under test to answer only the question "was this method called?"
As for the structure of the test method itself, yes, this is still asynchronous code and, as such, requires asynchronous testing. So using an expectation and waiting for it is correct. The fact that your app uses async/await to express asynchronousness does not magically change that! (You can decrease the verbosity of this by writing a utility method that creates a BOOL predicate expectation and waits for it.)
I don't know if you already find a solution to your question, but here is my contribution to other developers facing the same problem.
I was in the same situation as you, and I solved the problem by using Combine to notify the tested class that the method was called.
Let's say that we have this method to test:
func submitButtonPressed() {
Task {
await self.interactor?.fetchSections()
}
}
We should start by mocking the interaction:
import Combine
final class MockedInteractor: ObservableObject, SomeInteractorProtocol {
#Published private(set) var fetchSectionsIsCalled = false
func fetchSection async {
fetchSectionsIsCalled = true
// Do some other mocking if needed
}
}
Now that we have our mocked interactor we can start write unit test:
import XCTest
import Combine
#testable import YOUR_TARGET
class MyClassTest: XCTestCase {
var mockedInteractor: MockedInteractor!
var myClass: MyClass!
private var cancellable = Set<AnyCancellable>()
override func setUpWithError() throws {
mockedInteractor = .init()
// the interactor should be injected
myClass = .init(interactor: mockedInteractor)
}
override func tearDownWithError() throws {
mockedInteractor = nil
myClass = nil
}
func test_submitButtonPressed_should_callFetchSections_when_Always(){
//arrage
let methodCallExpectation = XCTestExpectation()
interactor.$fetchSectionsIsCalled
.sink { isCalled in
if isCalled {
methodCallExpectation.fulfill()
}
}
.store(in: &cancellable)
//acte
myClass.submitButtonPressed()
wait(for: [methodCallExpectation], timeout: 1)
//assert
XCTAssertTrue(interactor.fetchSectionsIsCalled)
}
There was one solution suggested here (#andy) involving injecting the Task. There's a way to do this by the func performing the task returning the Task and allows a test to await the value.
(I'm not crazy about changing a testable class to suit the test (returning the Task), but it allows to test async without NSPredicate or setting some arbitrary expectation time (which just smells)).
#discardableResult
func submitButtonPressed() -> Task<Void, Error> {
Task { // I'm allowed to omit the return here, but it's returning the Task
await self.interactor?.fetchSections()
}
}
// Test
func testSubmitButtonPressed() async throws {
let interactor = MockInteractor()
let task = manager.submitButtonPressed()
try await task.value
XCTAssertEqual(interactor.sections.count, 4)
}
I answered a similar question in this post: https://stackoverflow.com/a/73091753/2077405
Basically, given code defined like this:
class Owner{
let dataManager: DataManagerProtocol = DataManager()
var data: String? = nil
init(dataManager: DataManagerProtocol = DataManager()) {
self.dataManager = dataManager
}
func refresh() {
Task {
self.data = await dataManager.fetchData()
}
}
}
and the DataManagerProtocol is defined as:
protocol DataManagerProtocol {
func fetchData() async -> String
}
a mock/fake implementation can be defined:
class MockDataManager: DataManagerProtocol {
func fetchData() async -> String {
"testData"
}
}
Implementing the unit test should go like this:
...
func testRefreshFunctionFetchesDataAndPopulatesFields() {
let expectation = XCTestExpectation(
description: "Owner fetches data and updates properties."
)
let owner = Owner(mockDataManager: DataManagerProtocol())
// Verify initial state
XCTAssertNil(owner.data)
owner.refresh()
let asyncWaitDuration = 0.5 // <= could be even less than 0.5 seconds even
DispatchQueue.main.asyncAfter(deadline: .now() + asyncWaitDuration) {
// Verify state after
XCTAssertEqual(owner.data, "testData")
expectation.fulfill()
}
wait(for: [expectation], timeout: asyncWaitDuration)
}
...
Hope this makes sense?

Weak reference becomes nil after dispatch into serial queue

I've toyed around with Swift Playground and noticed the following issue:
The code below describes a series of object connected to one another in the following way:
objectC --> ObjectB -- weak ref to another C --> another C --> Object B etc..
Each objectC consists of
- a ref to a object B
- a weak ref to a delegate => this one becomes nil!!
Each objectB consists of
- A var integer
- A weak ref to another object C
The code does the following:
objectC call a function, say run(), which will evaluate (objectB.weak_ref_to_another_C), and call objectB.weak_ref_to_another_C.run() in a serial Queue.
After calling .run() a couple of times, C's delegate mysteriously becomes nil....
Any idea what I'm doing wrong? To start the code, simply call test_recursive_serial() on Swift Playground.
let serialQueue = DispatchQueue(label: "myQueue");
public protocol my_protocol:class {
func do_something(ofValue:Int,completion:((Int) -> Void))
}
public class classA:my_protocol {
public let some_value:Int;
public init(value:Int){
self.some_value = value;
}
public func do_something(ofValue:Int,completion:((Int) -> Void)) {
print("A:\(some_value) in current thread \(Thread.current) is executing \(Thread.current.isExecuting)");
if self.some_value == ofValue {
completion(ofValue);
}
}
}
public class classB {
public weak var jump_to_C:classC?;
public var value:Int = 0;
}
public class classC {
weak var delegate:my_protocol?{
willSet {
if (newValue == nil) { print("target set to nil") }
else { print("target set to delegate") }
}
}
var someB:classB?
public func do_something_else() {
print(self.delegate!)
}
public func do_another(withValue:Int,completion:((Int) -> Void)) {
}
public func run(completion:#escaping ((Int) -> Void)) {
print("\(self.someB?.value)");
assert(self.delegate != nil, "not here");
if let obj = someB?.jump_to_C, obj !== self {
someB?.value += 1;
print("\(someB!)")
usleep(10000);
if let value = someB?.value, value > 100 {
completion(someB!.value);
} else {
serialQueue.async {
print("lauching...")
obj.run(completion: completion);
}
}
}else{
print("pointing to self or nil...\(someB)")
}
}
}
public func test_recursive_serial() {
let my_a = classA(value:100);
let arrayC:[classC] = (0..<10).map { (i) -> classC in
let c = classC();
c.delegate = my_a;
return c;
}
let arrayB:[classB] = (0..<10).map { (i) -> classB in
let b = classB();
let ii = (i + 1 >= 10) ? 0 : i + 1;
b.jump_to_C = arrayC[ii]
return b;
}
arrayC.forEach { (cc) in
cc.someB = arrayB[Int(arc4random())%arrayB.count];
}
arrayC.first!.run() { (value) in
print("done!");
}
}
Important note: if test_recursive_serial() content is directly called from the playground, that is not through a function, the problem doesn't appear.
Edit: You'll need to add 'PlaygroundPage.current.needsIndefiniteExecution = true' to the playground code.
Edit: Ok, I feel I need to add this. Big mistake on my side, test_recursive_serial() doesn't keep a reference on any of the called objects, so obviously, they all become nil after the code leaves the function. Hence the problem. Thanks to Guy Kogus for pointing that out.
Final edit: Adding this, in the hope it might help. Swift playground are great to test-drive code, but can sometime become very busy. Within the current issue, the solution requires to set the variables first, and then pass them to test_recursive_serial() which in turn adds to the chatty appearance of the playground. Here's another option to keep your code tidy and self-contained, while dealing with async functions of various flavours...
If you have an async task - one that doesn't fit into URL fetch -, say:
myObject.myNonBlockingTask(){ print("I'm done!"}
First, include XCTest at the top of your file.
import XCTest
then add the following:
func waitForNotificationNamed(_ notificationName: String,timeout:TimeInterval = 5.0) -> Bool {
let expectation = XCTNSNotificationExpectation(name: notificationName)
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
return result == .completed
}
finally, change your completion block to:
myObject.myNonBlockingTask(){
print("I'm done!")
let name = NSNotification.Name(rawValue: "foobar");
NotificationCenter.default.post(name:name , object: nil)
}
XCTAssert(waitForNotificationNamed("foobar", timeout: 90));
the full playground code will look like:
public func my_function() {
let somevar:Int = 123
let myObject = MyClass(somevar);
myObject.myNonBlockingTask(){
print("I'm done!")
let name = NSNotification.Name(rawValue: "foobar");
NotificationCenter.default.post(name:name , object: nil)
}
XCTAssert(waitForNotificationNamed("foobar", timeout: 90));
}
Playground will wait on the notification before going any further, and also generate an exception if it times out. All locally created objects will remain valid until the execution completes.
Hope this helps.
The main issue is that you're testing this in Playgrounds, which doesn't necessarily play nicely with multithreading. Following from this SO question, change the test_recursive_serial function to:
arrayC.first!.run() { (value) in
print("done! \(value)")
XCPlaygroundPage.currentPage.needsIndefiniteExecution = false
}
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
while XCPlaygroundPage.currentPage.needsIndefiniteExecution {
}
(You'll need to add import XCPlayground at the top of the code to make it work.)
If you don't add that code change, then my_a is released after you leave that function, which is why delegate becomes nil on the second call to run.
I also found that in run, if you don't call the completion closure in the else case like so:
public func run(completion:#escaping ((Int) -> Void)) {
...
if let obj = someB?.jump_to_C, obj !== self {
...
}else{
print("pointing to self or nil...\(someB)")
completion(-1) // Added fallback
}
}
Then the program gets stuck. By adding that it runs to the end, although I haven't actually worked out why.
Also, please get rid of all your ;s, this isn't Objective-C 😜

How to get the current queue name in swift 3

We have function like this in swift 2.2 for printing a log message with the current running thread:
func MyLog(_ message: String) {
if Thread.isMainThread {
print("[MyLog]", message)
} else {
let queuename = String(UTF8String: dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))! // Error: Cannot convert value of type '()' to expected argument type 'DispatchQueue?'
print("[MyLog] [\(queuename)]", message)
}
}
These code no longer compile in swift 3.0. How do we obtain the queue name now?
As Brent Royal-Gordon mentioned in his message on lists.swift.org it's a hole in the current design, but you can use this horrible workaround.
func currentQueueName() -> String? {
let name = __dispatch_queue_get_label(nil)
return String(cString: name, encoding: .utf8)
}
If you don't like unsafe pointers and c-strings, there is another, safe solution:
if let currentQueueLabel = OperationQueue.current?.underlyingQueue?.label {
print(currentQueueLabel)
// Do something...
}
I don't know any cases when the currentQueueLabel will be nil.
Now DispatchQueue has label property.
The label you assigned to the dispatch queue at creation time.
var label: String { get }
It seems been existed from first, maybe not been exposed via public API.
macOS 10.10+
And please use this only to obtain human-readable labels. Not to identify each GCDQ.
If you want to check whether your code is running on certain GCDQ, you can use dispatchPrecondition(...) function.
This method will work for both OperationQueue and DispatchQueue.
func printCurrnetQueueName()
{
print(Thread.current.name!)
}
Here's a wrapper class that offers some safety (revised from here):
import Foundation
/// DispatchQueue wrapper that acts as a reentrant to a synchronous queue;
/// so callers to the `sync` function will check if they are on the current
/// queue and avoid deadlocking the queue (e.g. by executing another queue
/// dispatch call). Instead, it will just execute the given code in place.
public final class SafeSyncQueue {
public init(label: String, attributes: DispatchQueue.Attributes) {
self.queue = DispatchQueue(label: label, attributes: attributes)
self.queueKey = DispatchSpecificKey<QueueIdentity>()
self.queue.setSpecific(key: self.queueKey, value: QueueIdentity(label: self.queue.label))
}
// MARK: - API
/// Note: this will execute without the specified flags if it's on the current queue already
public func sync<T>(flags: DispatchWorkItemFlags? = nil, execute work: () throws -> T) rethrows -> T {
if self.currentQueueIdentity?.label == self.queue.label {
return try work()
} else if let flags = flags {
return try self.queue.sync(flags: flags, execute: work)
} else {
return try self.queue.sync(execute: work)
}
}
// MARK: - Private Structs
private struct QueueIdentity {
let label: String
}
// MARK: - Private Properties
private let queue: DispatchQueue
private let queueKey: DispatchSpecificKey<QueueIdentity>
private var currentQueueIdentity: QueueIdentity? {
return DispatchQueue.getSpecific(key: self.queueKey)
}
}
This works best for me:
/// The name/description of the current queue (Operation or Dispatch), if that can be found. Else, the name/description of the thread.
public func queueName() -> String {
if let currentOperationQueue = OperationQueue.current {
if let currentDispatchQueue = currentOperationQueue.underlyingQueue {
return "dispatch queue: \(currentDispatchQueue.label.nonEmpty ?? currentDispatchQueue.description)"
}
else {
return "operation queue: \(currentOperationQueue.name?.nonEmpty ?? currentOperationQueue.description)"
}
}
else {
let currentThread = Thread.current
return "UNKNOWN QUEUE on thread: \(currentThread.name?.nonEmpty ?? currentThread.description)"
}
}
public extension String {
/// Returns this string if it is not empty, else `nil`.
public var nonEmpty: String? {
if self.isEmpty {
return nil
}
else {
return self
}
}
}

Compiler error for nested class with override func - Swift Xcode6

I have a simple Cocoa Touch Framework project with Swift code only. In my unit test class I want to do mocking so I created a mock class which inherits from the type I want to mock:
func testFirstClassMocking() {
class MockSecondClass: SecondClass {
var mockedResult = "My mocked value"
override func printSecondLogEntry(logEntry: String) -> String {
return mockedResult
}
}
let mock = MockSecondClass()
var firstClass = FirstClass(secondClass: mock)
let result = firstClass.printFirstLogEntry("whatever")
XCTAssertEqual("My mocked value", result);
}
This result in a generic compiler error:
Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
Now, when I take the nested class out of the function and nest just in my testing class - everything is great. Code compiles and my unit test runs great. Is class nesting in functions not allowed any more?
My Xcode ver: Version 6.0.1 (6A317)
EDIT: one other thing - if I remove the override of the func - the compiler has no issues. Obviously I need the override func to be able to return a value I need in my unit test when my mock object runs.
I thought you might want to know that the following 'mock' of your mock test is compiling and passing. Let me know if I missed something about your code as it is in your question. If I did not miss anything, however, then the cause of the error is something about your code that did not make into the question. Hope that helps you either find the culprit or reformulate the question:
import XCTest
class FirstClass {
let secondClass: SecondClass
init(secondClass: SecondClass) {
self.secondClass = secondClass
}
func printFirstLogEntry(entry: String) -> String {
var fullLog = self.secondClass.printSecondLogEntry(entry)
return fullLog
}
}
class SecondClass {
func printSecondLogEntry(logEntry: String) -> String {
return logEntry
}
}
class CommandLineTests: XCTestCase {
func testFirstClassMocking() {
class MockSecondClass: SecondClass {
override func printSecondLogEntry(logEntry: String) -> String {
return logEntry
}
}
let mock = MockSecondClass()
var firstClass = FirstClass(secondClass: mock)
let result = firstClass.printFirstLogEntry("whatever")
XCTAssertEqual("whatever", result);
}
}