stevo
12/3/2017 - 12:17 PM

RubyOnRails testing antipatterns - examples

RubyOnRails testing antipatterns - examples

class CloseOrder
  def initialize(order)
    @order = order
  end
  
  def call
    update_closed_at_timestamp
    send_notification
  end
  
  private
  
  def update_closed_at_timestamp
    @order.touch(:closed_at)
  end
  
  def send_notification
    OrderMailer.order_closed_notification(@order).deliver_now
  end  
end
describe CloseOrder do
  describe '#call' do
    it 'delivers order closed notification to customer' do
      order = create(:order, customer_email: 'tony@stark.com')  
      service = CloseOrder.new(order)
    
      expect { 
        service.call 
      }.to change { ActionMailer.deliveries.count }.by(1)

      notification = ActionMailer.deliveries.last
      expect(notification).to have_attributes(subject: 'Order closed!', recipients: ['tony@stark.com'])
    end
  
    it 'updates closed_at with current time' do
      order = create(:order)  
      service = CloseOrder.new(order)
    
      travel_to(DateTime.new(2017, 1, 1, 12)) do
        expect {
          service.call
        }.to change { order.reload.closed_at }.to(DateTime.new(2017, 1, 1, 12))
      end
    end
  end
end

describe CloseOrder do
  describe '#call' do
    it 'sends notification to customer and updates closed_at' do
      order = create(:order)
      service = CloseOrder.new(order)
      allow(service).to receive(:send_notification)
      allow(service).to receive(:update_closed_at_timestamp)
      
      service.call
      
      expect(service).to have_received(:send_notification)
      expect(service).to have_received(:update_closed_at_timestamp)
    end
  end
  
  describe '#send_notification' do
    it 'delivers order closed notification to customer' do
      order = create(:order, customer_email: 'tony@stark.com')  
      service = CloseOrder.new(order)
    
      expect { 
        service.send(:send_notification)) 
      }.to change { ActionMailer.deliveries.count }.by(1)

      notification = ActionMailer.deliveries.last
      expect(notification).to have_attributes(subject: 'Order closed!', recipients: ['tony@stark.com'])
    end
  end

  describe '#update_closed_at_timestamp' do
    it 'updates closed_at with current time' do
      order = create(:order)  
      service = CloseOrder.new(order)
    
      travel_to(DateTime.new(2017, 1, 1, 12)) do
        expect {
          service.send(:update_closed_at_timestamp)
        }.to change { order.reload.closed_at }.to(DateTime.new(2017, 1, 1, 12))
      end
    end
  end  
end