trailblazer
trailblazer copied to clipboard
how to stub #success?
Hi
sorry this is not an issue my question is, how to stub an operation result
let say I have opA and opB
there is a step in opB that depends on opA, and I want to mock failing operation for opA however because
operation = opA.call
creates anonymous instance class, I can't stub operation.success?
result
thanks in advance
Come over to the gitter channel - you can get more responses there.
Having said that, you just need to call your operation with the params, that would cause it to fail. It could be even an operation that has one step, that returns false for example.
opA.call
should be executing operation however, it's hard to tell what's going on without seeing the rest of your code.
I believe you have something like
class A < Trailblazer::Operation
step Nested( B )
and you want to make B
return a failure result? I am neither a mocking expert nor a supporter of this flawed testing approach, since it always creates a wrong feeling of security. Can't you invoke the test in a way the inner op fails? There are ways, though, how to do that with mocking, e.g. you could mock the result from B.call
?
said @apotonick , @saiqulhaq I don't do this kind of approach, but if really need to this, here is the way to go:
require 'test_helper'
class StubTest < ActiveSupport::TestCase
class OperationMock < OpenStruct
def success?
success
end
def failure?
!success
end
end
class OpA < Trailblazer::Operation
step :run_opa!
def run_opa!(opts, params:, **)
params[:force_return]
end
end
class OpB < Trailblazer::Operation
step :check_opa!
def check_opa!(opts, params:, **)
res = OpA.(params)
res.success?
end
end
test "stub operation failure" do
OpA.stub(:call, OperationMock.new(success: false)) do
res = OpB.(force_return: true)
refute res.success?
end
end
test "stub operation success" do
OpA.stub(:call, OperationMock.new(success: true)) do
res = OpB.(force_return: false)
assert res.success?
end
end
end
If you need something else from the operation, you can write the method on OperationMock
to keep the interface similar
ps: you know what I do? If I connect to some external service on OpA
I stub this connection, not the whole operation, so in my test, I guarantee that both operations are working correctly together, just an idea 😉
thanks @konung I will go to Gitter channel instead later
@apotonick yes I can invoke test in a way the inner operation fails if the case is same as your example code
class A < Trailblazer::Operation
step Nested( B )
but i have different case here, sorry I forget which one, I have been working on another feature now, so much backlog :) Thanks for your suggestion
@fernandes awesome, thanks for sharing your code
ps: you know what I do? If I connect to some external service on OpA I stub this connection, not the whole operation, so in my test, I guarantee that both operations are working correctly together, just an idea 😉
Yes I'm agree with you, it makes our code is easier to test
I find this an interesting problem and we should at least have a good solution to it. :coffee:
@apotonick what's in your mind?
Right now, this:
At the moment, it seems the problem is present again. I tried the method described above and also tried substituting the following options:
it 'call to suboperation' do
expect(Api::V1::Lib::Operation::WaitlistRequests::UnsuspendWaitlistRequests).to receive(:call).and_return(Trailblazer::Operation::Result.new(true, {}))
result
end
it 'call to suboperation' do
expect(Api::V1::Lib::Operation::WaitlistRequests::UnsuspendWaitlistRequests).to receive(:call).and_return(Trailblazer::Activity::Railway::End::Success.new(semantic: :success))
result
end
This leads to the following problem:
Could you please tell me what I am doing wrong?