Closed duribreux closed 8 years ago
Quickly glancing over the code I see one thing:
Shouldn't the line
slug, script, completion in completion(Result.Success(())) // Problem?
be
slug, script, completion in completion(Result.Success()) // Note the removed extra ()
I tried both solution at some point, both giving the same output. I spent quite a lot of time poking around to find a solution and forgot to undo this.
Looking into my code I've found this mock which is working just fine.
self.clientMock().disconnectStub.on(any()) { completion in
completion(Result.Success())
}
self.clientMock().disconnectMock.expect(any())
Hi @duribreux,
would be nice to see your actual (compilable) code, e.g. in your Executed code snippet: What is completion block. Where does it come from? The send Result also looks not correct (as it sends as string).
handler.start(crop.getSlug(), script: subscribedCrop.getScript()) {
startResult in
switch startResult {
case .Success: completion(Result.Success(crop)) // case Result.Success(Void): Do something else
case .Error(let error): completion(Result.Error(error))
}
}
Sadly I can't share my project, it's not open source and there will be a business behind.
This is the full concerned method. Hope it can help you to understand what I'm trying to achieve.
private func startCrop(crop: Crop, completion: (Result<Crop>) -> ()) {
if (!crop.activated()) {
completion(Result.Error(CropException.Inactive(crop: crop)))
} else {
do {
let subscribedCrop = try self.databaseCrop.retrieve(crop)
let handler: ExecutionHandlerOperations = handlerFactory.get()
handler.start(crop.getSlug(), script: subscribedCrop.getScript()) {
startResult in
switch startResult {
case .Success: completion(Result.Success(crop))
case .Error(let error): completion(Result.Error(error))
}
}
} catch {
completion(Result.Error(error))
}
}
}
Those are 2 different completion blocks. The one relative to the private function is (Result<Crop>) -> ()
and the mocked one relative to the start
method is (Result<Void>) -> ()
If I don't mock my ExecutionHandler
(Associated to ExecutionHandlerOperations
protocol) I successfully reach my handler.start
completion Success case.
On the other hand, I can see in debug mod that I jump from:
handler.start(crop.getSlug(), script: subscribedCrop.getScript()) {
to...}
associated to the start method. And then...Execution doesn't seem to go into my handler.start
completion block. Which would explain the stubbing exception I guess.
PS: If it's not helping I'll take the time to - try - to reproduce on a basic project.
Hey @duribreux, can you please verify that your expected slug and script match the actual values, for example, by invoking your stub right after having set up the behavior:
handlerMock.startStub.invoke((self.slug, self.script, { _ in }))
I've took some times to create a sample project to hopefully being able to reproduce the problem but everything worked just fine.. The sample is a bit easier (no injection, fewer methods) but the behavior is pretty much the same.
Conclusion: There is probably a sneaky bug in my library. Since it doesn't seem related to Dobby, I guess you can close this issue. I can eventually keep you updated when I'll find the solution.
If you want to take a look, just pod install
, open workspace and cmd+u
Thanks for your time.
Gosh I hate myself.
In my injection overriding I wrote:
binder
.bind(ExecutionHandlerOperations.self)
.tagged(with: APSModule.ExecutionHandlerProvider.self)
.to(factory: MockExecutionHandler.init) // Creates a new instance when I call the get() method
Instead of:
binder
.bind(ExecutionHandlerOperations.self)
.tagged(with: APSModule.ExecutionHandlerProvider.self)
.to(value: MockExecutionHandler()) // Returns the same instance
During the execution of start
, handlerFactory.get()
was called, creating a new instance of MockExecutionHandler
which was obviously not the same object than my mock-ed one in my test causing the stub unexpected behavior...
let handler: ExecutionHandlerOperations = handlerFactory.get() // This is the freakin (Function) I guess
And yes.. that was obvious :|
Thanks for your time and work !
@duribreux cool! Let us know if you have any further questions :)
Working on my unit tests I faced an explicit error:
Dobby.StubError<(Swift.String, Swift.String, *******.Result<()> -> ()), ()>.UnexpectedInteraction("slug", "script", (Function))
The thing is, I already mock-ed a lot of methods looking pretty much the same without any trouble.
Relevant classes / enum:
Test mock:
Executed code:
As you can see, my stub should be typed as a
Result<()> -> ()
, instead of that I've got a(Function)
. Is it a bug or I am doing something wrong ?PS: If I don't mock my ExecutionHandler and implement start this way the test passes:
Note: The code below is a working example of a similar code.
And in the passing test:
I don't see any relevant difference. Any idea ? Am I missing something obvious ?