A very simple library for mocking Tzu in RSpec
TzuMock.success(klass).returns(result) #=> Successful Outcome
TzuMock.invalid(klass).returns(error) #=> Invalid Outcome
TzuMock.failure(klass).returns(error) #=> Failed Outcome
Consider this Tzu command:
class UpdateUser
include Tzu
include Tzu::Validation
def call(params)
raise ArgumentError.new('I should be mocked!')
end
end
There are two ways this might need to be mocked. The first happens when the Tzu command is invoked without a block:
outcome = UpdateUser.run(params)
The second is when the command is invoked with a block, as in this mock controller:
class MockController
attr_reader :method_called
def update(params = {})
UpdateUser.run(params) do
success do |result|
@method_called = :success
end
invalid do |error|
@method_called = :invalid
end
failure do |error|
@method_called = :failure
end
end
end
end
In both cases, the use of TzuMock is the same. First, we'll mock at the simple invocation:
describe UpdateUser do
let(:result) { 'Desired Result' }
let(:error) { { error: 'ERROR' } }
let(:params) { { last_name: 'Turner' } }
context 'success' do
before { TzuMock.success(UpdateUser).returns(result) }
let(:outcome) { UpdateUser.run(params) }
it 'mocks a successful outcome and allows parameters to be verified' do
expect(outcome.success?).to be true
expect(outcome.result).to eq result
expect(outcome.type).to be nil
expect(UpdateUser).to have_received(:run).with(params)
end
end
context 'invalid' do
before { TzuMock.invalid(UpdateUser).returns(error) }
let(:outcome) { UpdateUser.run(params) }
it 'mocks an invalid outcome and allows parameters to be verified' do
expect(outcome.success?).to be false
expect(outcome.result).to eq error
expect(outcome.type).to eq :validation
expect(UpdateUser).to have_received(:run).with(params)
end
end
context 'failure' do
before { TzuMock.failure(UpdateUser).returns(error) }
let(:outcome) { UpdateUser.run!(params) }
it 'mocks a failed outcome and allows parameters to be verified' do
expect(outcome.success?).to be false
expect(outcome.result).to eq error
expect(outcome.type).to eq :execution
expect(UpdateUser).to have_received(:run!).with(params)
end
end
end
TzuMock mocks both run
and run!
, and spies on the class so that you can verify the parameters that were passed.
Next, we'll mock the controller:
describe UpdateUser do
let(:result) { 'Desired Result' }
let(:error) { { error: 'ERROR' } }
let(:params) { { last_name: 'Turner' } }
let(:controller) { MockController.new }
context 'success' do
before { TzuMock.success(UpdateUser).returns(result) }
it 'mocks a successful outcome and allows parameters to be verified' do
controller.update(params)
expect(UpdateUser).to have_received(:run).with(params)
expect(controller.method_called).to eq :success
end
end
context 'invalid' do
before { TzuMock.invalid(UpdateUser).returns(error) }
it 'mocks a successful outcome and allows parameters to be verified' do
controller.update(params)
expect(UpdateUser).to have_received(:run).with(params)
expect(controller.method_called).to eq :invalid
end
end
context 'failure' do
before { TzuMock.failure(UpdateUser).returns(error) }
it 'mocks a successful outcome and allows parameters to be verified' do
controller.update(params)
expect(UpdateUser).to have_received(:run).with(params)
expect(controller.method_called).to eq :failure
end
end
end
TzuMock effortlessly passes your desired outcome to the appropriate block.
TzuMock converts your result hash attributes into methods by default.
# if you return this result
before { TzuMock.success(UpdateUser).returns({name: 'me'}) }
# you can access it on this way
outcome = UpdateUser.run(params)
outcome.result.name
# even if you have result as array contains hashs
before { TzuMock.success(UpdateUser).returns([{name: 'me'}]) }
# you can access it on this way
outcome = UpdateUser.run(params)
outcome.result.first.name
By default, TzuMock mocks the run
and run!
methods,
but you can add more methods to that list if your Tzu classes have another interface.
# spec/spec_helper.rb
TzuMock.configure { |config| config.stub_methods = [:go, :go!] }