MockProvider does not call promise's callback
daneov opened this issue · comments
The following snippet shows a reproducible case in which neither success nor failure on the promise's part is called.
This seems to be in part due to the Networking
instance being deallocated (the weak self check) returns since it is nil.
How can I work around this?
final class MockProviderSpec: QuickSpec {
override func spec() {
describe("Test") {
it("Passes") {
let fetcher = APIFetcher()
waitUntil { done in
fetcher.request(request: CustomEndpoint.test).then({ _ in
done()
}).fail({ error in
done()
})
}
}
}
}
}
class APIFetcher {
var mockClosure: ((RequestConvertible) -> Mock?)?
func defaultClosure(_ request: RequestConvertible) -> Mock?{
return Mock(json: [:])
}
func request(request: CustomEndpoint) -> NetworkPromise {
let networking = Networking<CustomEndpoint>(mode: .sync,
mockProvider: MockProvider<CustomEndpoint>(defaultClosure)
)
return networking.request(request)
}
}
enum CustomEndpoint: RequestConvertible {
static var baseUrl: URLStringConvertible?
static var headers: [String : String] = [:]
var request: Request {
return Request.post("mock://derp")
}
case test
}
You could make networking
an instance var in your test and then inject it to APIFetcher
for example.
Sorry, due to oversimplifying the real case got lost :)
Here is a gist containing the actual case.
The execute<T>(request: T) -> NetworkPromise
is required by the protocol, and relied upon by my services.
If I want to test a service, I thus mock the APIClient
in them, and the Networking
instance is configured in the APIMockClient
, since in the real world, it is also responsible for configuring the Networking
's headers and authentication token.
Now, in a real world example this approach works:
func execute<T>(request: T,
mockProvider: MockProvider<T>? = nil) -> NetworkPromise where T: RequestConvertible {
let networking = Networking<T>(mode: .async, mockProvider: mockProvider)
networking.configureHeaders()
networking.configure(token: userManager.accessToken)
return networking.request(request).validate()
So I am a bit confused here, as the exact same approach is used.
When I use Malibu
I usually keep a reference to Networking
class somewhere. In your case it's not easy to find a workaround without changing the code. It would be easier if you had a generic APIMockClient
with networking being an instance var, but it doesn't follow func execute<T>(request: T)
method from APIClientMethods
protocol.
I ended up making sure the Networking
instance doesn't deallocate in the tests by retaining the object as follows:
func execute<T>(request: T,
mockProvider: MockProvider<T>? = nil) -> NetworkPromise where T: RequestConvertible {
let networking = Networking<T>(mode: .async, mockProvider: mockProvider)
return networking.request(request).validate().always({ _ in _ = networking })
Thanks for the help!