/tzu_mock

Simple library for mocking Tzu in RSpec

Primary LanguageRubyMIT LicenseMIT

Tzu Mock

A very simple library for mocking Tzu in RSpec

Usage

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.

Hash Result

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

Configuration

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!] }