collectiveidea / interactor

Interactor provides a common interface for performing complex user interactions.
MIT License
3.36k stars 212 forks source link

Testing .rollback #202

Closed hirokihokari closed 2 years ago

hirokihokari commented 3 years ago

The author of #100 @concept47 seems to have realized they "could just call .new.rollback", but I still don't get it. For example, in a classic active record rollback scenario like below, how would one test the behavior?

def rollback
  context.user.destroy
end

Perhaps it involves some sort of doubles? I've been neglecting tests for long and I'm losing touch of these testing techniques, let alone specific library syntax (I'm using RSpec).

Could someone give me a pointer?

chubchenko commented 3 years ago

# app/interactors/my_interactor.rb

class MyInteractor
  include ::Interactor

  def call
    context.fail!(message: 'Something went wrong')
  end

  def rollback
    context.user.destroy
  end
end

# spec/interactors/my_interactor_spec.rb

RSpec.describe MyInteractor do
  describe '#rollback' do
    subject(:context) { described_class.new(user: create(:user)) }

    it 'deletes user' do
      expect do 
        context.rollback
      end.to change(User, :count).from(1).to(0)
    end
  end
end
hirokihokari commented 2 years ago

@chubchenko

Thank you! Your code gave me a hint. Since interactors are not supposed to be interested in destroy's implementation, I think this would be a more efficient:

RSpec.describe MyInteractor do
  describe '#rollback' do
    let(:created_user) { double(:user) }
    let(:instance) { described_class.new(user: created_user) }

    it 'calls destroy on record' do
      expect(created_user).to receive(:destroy)

      instance.rollback
    end
  end
end