I have a class for that I want to write unit test. This class has a dependency, which is a generic class, that I want to mock.
This is the class I want to test.
class ClassToTest: SomeProtocol {
private let dependency = DependencyClass<AnotherClass>()
init() {
//Some Code Here
}
}
class DependencyClass<General: AnotherClassProtocol> {
func getData(from general: General) -> AnyPublisher<Data, Error> {
//Some Code Here
}
}
What I tried
class ClassToTest: SomeProtocol {
private let dependency: DependencyClassProtocol
init(_ dependency: DependencyClassProtocol = DependencyClass<AnotherClass>()) {
//Some Code Here
self. dependency = dependency
}
}
class DependencyClass<General: AnotherClassProtocol>: DependencyClassProtocol {
func getData(from general: General) -> AnyPublisher<Data, Error> {
//Some Code Here
}
}
protocol DependencyClassProtocol {
associatedtype General
func getData(from general: General) -> AnyPublisher<Data, Error>
}
This approach gives me error "Protocol can an only be used as a generic constraint because it has Self or associated type requirements".
How can I Mock the DependencyClass to test the exact behaviour of ClassToTest.
Related
I am new to Swift, but I have plenty of experience in other languages like Java, Kotlin, Javascript, etc. It's possible that what I want to do is not supported by the language, and I've poured over the Swift Language Guide looking for the answer.
I want to implement the decorator pattern, using generics. I easily did this in Kotlin, and I'm porting the library to Swift.
class Result<T> {
let result: T?
let error: NSError?
init(result: T?, error: NSError?) {
self.result = result
self.error = error
}
}
protocol DoSomething {
associatedtype T
func doSomething() -> Result<T>
}
protocol StoreSomething {
associatedtype T
func storeSomething(thing: Result<T>)
}
/*
* DOES NOT COMPILE
*/
class StoringSomething<T> {
private let delegate: DoSomething
private let store: StoreSomething
init(delegate: DoSomething, store: StoreSomething) {
self.delegate = delegate
self.store = store
}
func doSomething() -> Result<T> {
let result = delegate.doSomething()
store.storeSomething(thing: result)
return result
}
}
I get a Protocol 'DoSomething' can only be used as a generic constraint because it has Self or associated type requirements error from the compiler. I've tried using a typealias and other ideas from SO and the Swift manual.
Thanks to #Sweeper's suggestion on associatedtype erasure you can implement the Decorator pattern with generics like so:
class AnyDoSomething<T>: DoSomething {
func doSomething() -> Result<T> {
fatalError("Must implement")
}
}
class AnyStoreSomething<T>: StoreSomething {
func storeSomething(thing: Result<T>) {
fatalError("Must implement")
}
}
class StoringSomething<T>: DoSomething {
private let delegate: AnyDoSomething<T>
private let store: AnyStoreSomething<T>
init(delegate: AnyDoSomething<T>, store: AnyStoreSomething<T>) {
self.delegate = delegate
self.store = store
}
func doSomething() -> Result<T> {
let result = delegate.doSomething()
store.storeSomething(thing: result)
return result
}
}
class DoSomethingNice<T>: AnyDoSomething<T> {
override func doSomething() -> Result<T> {
}
}
I'm trying to build an API pattern.
I have several different APIs that have the same functions for some, and some have additional functions that other APIs do not have and should not have access.
The problem with the protocol is that they all have access. How to limit access if the function is not override?
apiRequest:
class APIRequest {
static func loginCli(completion: (UserClinic) -> ()) {
}
static func loginFami(completion: (User) -> ()) {
}
static func loginDavid(completion: (UserDavid) -> ()) {
}
}
Protol and API:
protocol API {
func login<T>(completion: (T) -> ())
func saveClient()
}
extension API {
func saveClient() {
saveClient()
}
}
class FirstAPI: API {
func login<T>(completion: (T) -> ()) {
APIRequest.loginFami { (user) in
}
}
}
class SecondAPI: API {
func login<T>(completion: (T) -> ()) {
APIRequest.loginCli { (user) in
}
}
}
class ThreeAPI: API {
func login<T>(completion: (T) -> ()) {
APIRequest.loginDavid { (user) in
}
}
func saveClient() {
// Save client
}
}
View model:
class LoginViewModel {
var apiClient: API
init() {
// Below its good
apiClient = ThreeAPI()
apiClient.saveClient()
// Below its not good
apiClient = FirstAPI()
apiClient.saveClient() // I want this is not accessible
// Below its good
apiClient = SecondAPI()
apiClient.saveClient() // I want this is not accessible
}
}
In my case I need only the third API to have access to the function saveClient()
If you don't want the saveClient method on FirstAPI and SecondAPI, you need to extract that method to a separate protocol. Something like:
protocol APIThatCanLogin {
func login<T>(completion: (T) -> ())
}
protocol APIThatCanSave {
func saveClient()
}
class FirstAPI: APIThatCanLogin { }
class SecondAPI: APIThatCanLogin { }
class ThreeAPI: APIThatCanLogin, APIThatCanSave { }
But perhaps you should reconsider using protocols. At least in this example it doesn't offer any benefits.
Try this.
protocol API {
func login<T>(completion: (T) -> ())
}
extension API where Self: ThreeAPI {
func saveClient() {
}
}
In the above code, protocol API extension is only available to object of type ThreeAPI.
I've used ThreeAPI directly here. You can make a common type for all the classes that need saveClient() and use that type in place of ThreeAPI
Usage:
apiClient = ThreeAPI()
(apiClient as? ThreeAPI)?.saveClient()
apiClient = FirstAPI() //saveClient() not available
apiClient = SecondAPI() //saveClient() not available
Edit-1:
Create a CommonAPI parent class for all the classes that need saveClient() method.
class CommonAPI {
func saveClient() {
print("CommonAPI saveClient()")
}
}
Inherit ThreeAPI and FourAPI from CommonAPI
class ThreeAPI: CommonAPI, API {
func login<T>(completion: (T) -> ()) {
}
override func saveClient() {
print("ThreeAPI saveClient()")
}
}
class FourAPI: CommonAPI, API {
func login<T>(completion: (T) -> ()) {
}
override func saveClient() {
print("FourAPI saveClient()")
}
}
Simply use a switch statement to call saveClient() on all the objects of type CommonAPI.
apiClient = FourAPI()
apiClient = ThreeAPI()
apiClient = FirstAPI()
apiClient = SecondAPI()
switch apiClient {
case is CommonAPI:
(apiClient as? CommonAPI)?.saveClient()
default:
break
}
In this case, you won't need to parse each and every type.
There is not going to be a solution to this as described. The type API means "has the following methods and properties." You cannot assign something to a variable of type API and then say "but it doesn't have some of the methods." That violates LSP, which is the foundation of these kinds of types. Consider the following code:
func save(api: API) {
api.saveClient()
}
If the feature you're describing could be implemented, should this compile or not? If it did compile, and then it were called with FirstAPI(), what should happen then?
If you want saveClient to be a no-op (to do nothing), then that's very straightforward. Provide an empty default implementation:
extension API {
func saveClient() {}
}
If you want some APIs to be savable, and some not to be savable, then that's straightforward too:
protocol API {
func login<T>(completion: (T) -> ())
}
protocol SavableAPI: API {
func saveClient()
}
But the init method you've written cannot be made to work. It violates the underlying goal of having a type.
I am trying to use generic protocols and inject a concrete implementation but I get the following error: Protocol 'Repo' can only be used as a generic constraint because it has Self or associated type requirements at let repo: Repo
My code
protocol Repo{
associatedtype T
func doSomething() -> T
}
class MyRepo: Repo{
func doSomething() -> String{
return "hi"
}
}
class SomeClass {
let repo: Repo
init(repo: Repo) {
self.repo = repo
repo.doSomething()
}
}
class EntryPoint{
let someClass: SomeClass
init(){
someClass = SomeClass(repo: MyRepo)
}
}
Entry point is called first and sets up the dependency tree.
I think what you are looking for is something like this:
protocol Repo {
associatedtype T
func doSomething() -> T
}
class MyRepo: Repo{
func doSomething() -> String{
return "hi"
}
}
class SomeClass<A: Repo> {
let repo: A
init(repo: A) {
self.repo = repo
_ = repo.doSomething()
}
}
class EntryPoint{
let someClass: SomeClass<MyRepo>
init(){
someClass = SomeClass<MyRepo>(repo: MyRepo())
}
}
I have multiple protocols that have the same function name. Some protocols have associated types, where I can't figure out how to call the functions as I do in non-generic protocols. I get the error: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements
Here's what I'm trying to do:
protocol Serviceable {
associatedtype DataType
func get(handler: ([DataType] -> Void)?)
}
struct PostService: Serviceable {
func get(handler: ([String] -> Void)? = nil) {
print("Do something...")
}
}
protocol MyProtocol1: class {
associatedtype ServiceType: Serviceable
var service: ServiceType { get }
}
extension MyProtocol1 {
func didLoad(delegate: Self) {
print("MyProtocol1.didLoad()")
}
}
protocol MyProtocol2: class {
}
extension MyProtocol2 {
func didLoad(delegate: MyProtocol2) {
print("MyProtocol2.didLoad()")
}
}
class MyViewController: UIViewController, MyProtocol1, MyProtocol2 {
let service = PostService()
override func viewDidLoad() {
super.viewDidLoad()
didLoad(self as MyProtocol1) // Error here: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements
didLoad(self as MyProtocol2)
}
}
How can I specifically call the function from a generic protocol extension?
It's simple to achieve by turning the protocol into a generic (see below), or by creating a type eraser for these protocols, but this very strongly suggests that you have a design problem and you should redesign your classes and/or extensions. A collision like this suggests strongly that MyStruct is doing too many things itself because it's being pulled in multiple directions by MyProtocol1 and MyProtocol2. There should likely be two objects here instead. (Composition rather than inheritance.)
class MyStruct: MyProtocol1, MyProtocol2 {
let service = PostService()
func prot1Load<T: MyProtocol1>(t: T) {
t.didLoad()
}
func prot2Load<T: MyProtocol2>(t: T) {
t.didLoad()
}
init() {
prot1Load(self)
prot2Load(self)
}
}
To your particular example in the comments, I would use composition rather than inheritance. You're treating protocols like multiple-inheritance, which is almost never right. Instead compose out of things that conform to a protocol.
protocol LoadProviding {
func load()
}
struct MyLoader1: LoadProviding {
func load() {
print("MyLoader1.didLoad()")
}
}
struct MyLoader2: LoadProviding {
func load() {
print("MyLoader2.didLoad()")
}
}
protocol Loader {
var loaders: [LoadProviding] { get }
}
extension Loader {
func loadAll() {
for loader in loaders {
loader.load()
}
}
}
class MyStruct: Loader {
let service = PostService()
let loaders: [LoadProviding] = [MyLoader1(), MyLoader2()]
init() {
loadAll()
}
}
Of course you don't really have to have LoadProviding be a full struct. It could just be a function if that's all you need:
typealias LoadProviding = () -> Void
func myLoader1() {
print("MyLoader1.didLoad()")
}
func myLoader2() {
print("MyLoader2.didLoad()")
}
protocol Loader {
var loaders: [LoadProviding] { get }
}
extension Loader {
func loadAll() {
for loader in loaders {
loader()
}
}
}
class MyStruct: Loader {
let service = PostService()
let loaders: [LoadProviding] = [myLoader1, myLoader2]
init() {
loadAll()
}
}
If you have time to wade through a video on the subject, you may be interested in the Beyond Crusty: Real World Protocols talk from dotSwift. It's about this and similar problems.
Is there a standard way to make a "pure virtual function" in Swift, ie. one that must be overridden by every subclass, and which, if it is not, causes a compile time error?
You have two options:
1. Use a Protocol
Define the superclass as a Protocol instead of a Class
Pro: Compile time check for if each "subclass" (not an actual subclass) implements the required method(s)
Con: The "superclass" (protocol) cannot implement methods or properties
2. Assert in the super version of the method
Example:
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
Pro: Can implement methods and properties in superclass
Con: No compile time check
The following allows to inherit from a class and also to have the protocol's compile time check :)
protocol ViewControllerProtocol {
func setupViews()
func setupConstraints()
}
typealias ViewController = ViewControllerClass & ViewControllerProtocol
class ViewControllerClass : UIViewController {
override func viewDidLoad() {
self.setup()
}
func setup() {
guard let controller = self as? ViewController else {
return
}
controller.setupViews()
controller.setupConstraints()
}
//.... and implement methods related to UIViewController at will
}
class SubClass : ViewController {
//-- in case these aren't here... an error will be presented
func setupViews() { ... }
func setupConstraints() { ... }
}
There isn't any support for abstract class/ virtual functions, but you could probably use a protocol for most cases:
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Another workaround, if you don't have too many "virtual" methods, is to have the subclass pass the "implementations" into the base class constructor as function objects:
class MyVirtual {
// 'Implementation' provided by subclass
let fooImpl: (() -> String)
// Delegates to 'implementation' provided by subclass
func foo() -> String {
return fooImpl()
}
init(fooImpl: (() -> String)) {
self.fooImpl = fooImpl
}
}
class MyImpl: MyVirtual {
// 'Implementation' for super.foo()
func myFoo() -> String {
return "I am foo"
}
init() {
// pass the 'implementation' to the superclass
super.init(myFoo)
}
}
You can use protocol vs assertion as suggested in answer here by drewag.
However, example for the protocol is missing. I am covering here,
Protocol
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
Now every subclasses are required to implement the protocol which is checked in compile time. If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Note: this only works for the topmost class that implements the protocol. Any subclasses can blithely ignore the protocol requirements. – as commented by memmons
Assertion
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
However, assertion will work only in runtime.
This is what I usually do, to causes the compile-time error :
class SuperClass {}
protocol SuperClassProtocol {
func someFunc()
}
typealias SuperClassType = SuperClass & SuperClassProtocol
class Subclass: SuperClassType {
func someFunc() {
// ...
}
}
You can achieve it by passing function into initializer.
For example
open class SuperClass {
private let abstractFunction: () -> Void
public init(abstractFunction: #escaping () -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction()
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
print("my implementation")
}
)
}
}
You can extend it by passing self as the parameter:
open class SuperClass {
private let abstractFunction: (SuperClass) -> Void
public init(abstractFunction: #escaping (SuperClass) -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction(self)
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
(_self: SuperClass) in
let _self: SubClass = _self as! SubClass
print("my implementation")
}
)
}
}
Pro:
Compile time check for if each subclassimplements the required method(s)
Can implement methods and properties in superclass
Note that you can't pass self to the function so you won't get memory leak.
Con:
It's not the prettiest code
You can't use it for the classes with required init
Being new to iOS development, I'm not entirely sure when this was implemented, but one way to get the best of both worlds is to implement an extension for a protocol:
protocol ThingsToDo {
func doThingOne()
}
extension ThingsToDo {
func doThingTwo() { /* Define code here */}
}
class Person: ThingsToDo {
func doThingOne() {
// Already defined in extension
doThingTwo()
// Rest of code
}
}
The extension is what allows you to have the default value for a function while the function in the regular protocol still provides a compile time error if not defined