iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
自我挑戰組

Ruby on Rails 與它們相關的東西 II系列 第 19

Day19 - 匯入 excel-測試篇

前言

上篇匯入 Excel 實作,這篇以撰寫測試為主

實作

測試的寫法有蠻多種,這邊以其中一種為例,可參考此 pr

# spec/services/shops_excel/parser_spec.rb

require 'rails_helper'

RSpec.describe ShopsExcel::Parser do
  describe 'execute' do
    let(:excel_file) { Tempfile.new(%w[shops_import .xlsx]) }
    let(:excel) do
      file = excel_file
      file.binmode

      xlsx = Axlsx::Package.new
      workbook = xlsx.workbook
      workbook.add_worksheet(name: '商家清單') do |sheet|
        sheet.add_row(excel_titles)
        sheet.add_row(content_array1)
        sheet.add_row(content_array2)
      end
      xlsx.use_shared_strings = true
      xlsx.serialize(file)

      file.rewind
      file
    end
    let(:excel_titles) { ShopsExcel::Generator::TITLES }
    let(:content_array1) { ['shop_name_1', 'river@riverye.com', 'hello'] }
    let(:content_array2) { ['shop_name_2', 'test@riverye.com',  'world'] }

    subject { described_class.new.execute(excel) }

    context 'create shops successfully' do
      it 'data correctly' do
        expect { subject }.to change { Shop.count }.by(2)
        [content_array1, content_array2].each do |content_array|
          shop1 = Shop.find_by(name: content_array[0])
          expect(shop1).to have_attributes(
            name: content_array[0],
            email: content_array[1],
            note: content_array[2],
          )
        end
      end
    end

    context 'when return error' do
      let(:logger) { double }

      before do
        allow(Rails).to receive(:logger).and_return(logger)
      end

      def expect_error_message(error_message)
        expect(logger).to receive(:error).with(/\[ShopsExcel::Parser Error\] #{error_message}/)
        expect { subject }.to change { Shop.count }.by(0)
      end

      context 'when title is empty' do
        let(:excel_titles) { [nil, nil, nil] }
        let(:error_message) { '輸入資料有誤,比對 Excel 標頭與預期不同' }

        it { expect_error_message(error_message) }
      end

      context 'when data is empty' do
        let(:content_array1) { [nil, nil, nil] }
        let(:content_array2) { content_array1 }
        let(:error_message) { '無資料' }

        it { expect_error_message(error_message) }
      end

      context 'when data is duplicate' do
        let(:content_array2) { content_array1 }
        let(:error_message) { '有重複的商家名稱,請檢查' }

        it { expect_error_message(error_message) }
      end

      context 'when shop exists' do
        let(:shop) { create(:shop) }
        let(:content_array1) { [shop.name, shop.email, shop.note] }
        let(:content_array2) { ['shop_name_2', 'test@riverye.com', 'world'] }
        let(:error_message) { "有 1 筆已建立過: #{shop.name}" }

        it { expect_error_message(error_message) }
      end
    end
  end
end

小結

這篇其實是與上篇一起先寫好 code ,接著才開始寫文章,在寫測試過程中,有發現原本寫的方法要微調,這也是撰寫測試的好處,能發現一些沒留意到的眉眉角角 (說這麼多,就是擠牙膏嘛)

若有更好的寫法,歡迎留言和我說~

參考資料

  1. Roo GitHub

鐵人賽文章連結:https://ithelp.ithome.com.tw/articles/10272599
medium 文章連結:https://link.medium.com/sYWyCHbyRjb
本文同步發布於 小菜的 Blog https://riverye.com/

備註:之後文章修改更新,以個人部落格為主


上一篇
Day18 - 匯入 excel-應用篇
下一篇
Day20 - 用 Ruby on Rails 抓臺灣證券交易所資料-每日收盤行情
系列文
Ruby on Rails 與它們相關的東西 II30

尚未有邦友留言

立即登入留言