sabirvirtuoso/Mockit

How can I mock closure not class

hishamdubizzle opened this issue · 8 comments

Thank you for great effort. is there an example to mock closure?

Thanks. Can you be more specific and come up with a use case where you would want to mock closure. Till now Mockit only supports mocking classes.

it is a little bit complex example using RxSwift and Alamofire Router. this method will be called passing a closure which will be called when this method get token first from backend.

in my test case, i want to mock a closure and pass it to this method and verify that closure(token) is called once

func getResponseFromKombi<T>(closure: @escaping (String) -> URLRequestConvertible) -> Observable<T>{
	    return getTokenIfNotExist().flatMap { token in
	      return self.createObservable(closure(token)).debug("my probe")
	      }
	  }

I see. If we intend to mock it, then what that means is that we want to verify the action gets executed. But that can't be mocked. So instead interface-based approach should be used.

I already did this as a workaround. I created protocol with one method instead of closure.
but I submitted this ticket as it is better to have this feature in future.

By the way, I had many issues with Mockit even after using protocol. the method I want to mock should return Alamofire Router (URLRequestConvertible) which I failed to do after reading all example implementations. Any way, this is another issue I dont know if it is related to Mockit or my implementation. For now, I used traditional way by creating normal class with counter variable. I skipped Mockit for now as it didnt help me in my case. Again, it may be I who didnt understand Mockit well. I will give it another try in future

open class UIAlertControllerMock: UIAlertControllerImpl, Mock {

    open let callHandler: CallHandler

    public required init() {
        callHandler = CallHandlerImpl(withTestCase: XCTestCase(invocation: nil))
    }

    public init(testCase: XCTestCase) {
        callHandler = CallHandlerImpl(withTestCase: testCase)
    }

    open func instanceType() -> UIAlertControllerMock {
        return self
    }

    open override func actualUIAlertController() -> UIAlertController {
        return callHandler.accept(super.actualUIAlertController(), ofFunction: #function, atFile: #file, inLine: #line) as! UIAlertController
    }
}

Look at the last method where I return the actualAlertController instance. Your mock should extend the Implementation class and obtain the router instance from there and pass it here. So it can be something like

open override func getRouter() -> URLRequestConvertible {
    return callHandler.accept(super.actualRouter(), ofFunction: #function, atFile: #file, inLine: #line) as! URLRequestConvertible
}

Hope it helps :)

Many thanks. I will give it a try

Sure no problem. Any new feature or improvement recommendation is highly appreciable.

Hello,

May I have your email please so I can communicate with you. I need to know few things from you.

Have a good day.