Mock Third Party Classes (Firebase) in Swift

Mock third party classes (Firebase) in Swift

I've finally found an elegant way to solve this.

protocol FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)?)
}

extension FIRAuth: FIRAuthProtocol {
func signInAnonymously(completion: ((FIRUserProtocol?, Error?) -> Void)? = nil) {
let completion = completion as FIRAuthResultCallback?
signInAnonymously(completion: completion)
}
}

This way, there's no need to alter function names or argument labels.

Unit Testing email Sign Up Firebase

I completely forgot about this question and now knowing a lot more about Unit Testing, anyone else who is trying to do this. Don't. Tests are used to test the code that you have writing and not the core functionality of third party libraries. They should have their own tests.

Swift 4.2 - Returning classes created inside a function

Swift is capable of creating new types at runtime, but I don't think that it's currently possible to use that capability as a language user.

In Swift, not all statements are executable: there is code that is evaluated at compile-time only and results in no executable code. Class statements are one of these. The class scope is not evaluated at runtime to create a new class: the compiler sees a class statement, builds that class, and gives you a static reference to that class going forward. That way, no code is executed at your program's startup (or at any other time, for that matter) when you create a class. This contrasts to other languages, such as Python, where every statement is inherently executable, and executing a class statement actually creates a class.

This behavior is emphasized by errors when you try to use local variables inside of function-local classes:

func foo(int: Int) {
class Bar {
let f = int
// error: class declaration cannot close over value 'int' defined in outer
// scope
}
}

Sorting Through An Array Of Protocols, Looking for Parent Protocols

You just need to use compactMap along with the conditional coercion operation, as?.

compactMap


Returns an array containing the non-nil results of calling the given
transformation with each element of this sequence.

protocol ProtoOne { func someFunc() }
protocol ProtoTwo: ProtoOne { }

class ClassBasedOnOne: ProtoOne { func someFunc() { /* NOP */} }
class AnotherClassBasedOnOne: ProtoOne { func someFunc() { /* NOP */} }
class ClassBasedOnTwo: ProtoTwo { func someFunc() { /* NOP */} }
class AnotherClassBasedOnTwo: ProtoTwo { func someFunc() { /* NOP */} }

let arrayOfInstances: [ProtoOne] = [
ClassBasedOnOne(),
AnotherClassBasedOnOne(),
ClassBasedOnTwo(),
AnotherClassBasedOnTwo()
]

let protoTwos = arrayOfInstances.compactMap { $0 as? ProtoTwo }

compactMap is really simple, you can see its implementation here

This is a simple line that I honestly wouldn't bother extracting to a function, but if you insist:

func filterForInstances<T>(of: T.Type, from instances: [Any]) -> [T] {
return instances.compactMap { $0 as? T }
}

But it would be even better as an extension:

extension Sequence {
func keepingOnlyInstances<T>(of: T.Type) -> [T] {
return self.compactMap { $0 as? T }
}
}

Mock a token for flask unit tests - firebase-admin-python SDK

Put the logic behind an interface.

class TokenVerifier(object):
def verify(self, token):
raise NotImplementedError()

class FirebaseTokenVerifier(TokenVerifier):
def verify(self, token):
return auth.verify_id_token(token)

class MockTokenVerifier(TokenVerifier):
def verify(self, token):
# Return mock object that will help pass your tests.
# Or raise an error to simulate token validation failures.

Then make sure during unit tests your code uses the MockTokenVerifier.

It is also possible to create mock ID tokens, and stub out parts of the Admin SDK so that the auth.verify_id_token() runs normally during tests (see unit tests of the SDK). But I prefer the above solution since it's easier, cleaner and doesn't require messing with the internals of the SDK.

How to wait until get the response from component under test that use Alamofire? - Xcode

Hi @Raghad ak, welcome to Stack Overflow .

Your guess about the passage of time preventing the test to succeed is correct.

Networking code is asynchronous. After the test calls .sendActions(for: .touchUpInside) on your login button it moves to the next line, without giving the callback a chance to run.

Like @ajeferson's answer suggests, in the long run I'd recommend placing your Alamofire calls behind a service class or just a protocol, so that you can replace them with a double in the tests.

Unless you are writing integration tests in which you'd be testing the behaviour of your system in the real world, hitting the network can do you more harm than good. This post goes more into details about why that's the case.

Having said all that, here's a quick way to get your test to pass. Basically, you need to find a way to have the test wait for your asynchronous code to complete, and you can do it with a refined asynchronous expectation.

In your test you can do this:

expectation(
for: NSPredicate(
block: { input, _ -> Bool in
guard let label = input as? UILabel else { return false }
return label.text == "logged in successfully"
}
),
evaluatedWith: controllerUnderTest.lblValidationMessage,
handler: .none
)

controllerUnderTest.loginButton?.sendActions(for: .touchUpInside)

waitForExpectations(timeout: 10, handler: nil)

That expectation will run the NSPredicate on a loop, and fulfill only when the predicate returns true.

how to properly share a variable among some view controllers in swift?

I would recommend avoiding singletons here as well. The primary motivation is to make things testable. Here's a possible approach.

You have a User something like this:

struct User {
let userid: String
let email: String
}

Declare a protocol for managing your user. Using a protocol makes testing easier since you can create a mock that conforms to it.

protocol UserManagerProtocol {
func getSignedInUser() -> User?
func signIn(userid: String, password: String) -> User?
}

Declare your actual class that implements the protocol:

class UserManager: UserManagerProtocol {
fileprivate var signedInUser: User?
func getSignedInUser() -> User? {
return signedInUser
}
func signIn(userid: String, password: String) -> User? {
//call your server to sign in user
// if sign in fails, return nil
// if sign in works, create a User object
signedInUser = User(userid: userid, email: "email retrieved from server")
return signedInUser
}
}

Add a reference in your view controllers, but declare it using the protocol, not the actual class. Again, this allows for mocking.

class HomeVC: UIViewController {
var userManager: UserManagerProtocol?
}
class PostVC: UIViewController {
var userManager: UserManagerProtocol?
}

Finally, in your AppDelegate, when you launch the app, create a single instance of your UserManager, store it in the AppDelegate, and pass it to all your view controllers. In this example, I've obviously left out a lot of stuff because I don't know what your AppDelegate looks like.

class AppDelegate: NSObject, UIApplicationDelegate {
var userManager: UserManagerProtocol?

func applicationDidFinishLaunching(_ application: UIApplication) {
userManager = UserManager()

//when setting up your tab bar controllers, pass the userManager instance to each of them
}
}


Related Topics



Leave a reply



Submit