※ この物語はお仕事でのお話です
モノリシックな Rails
↓
API がいくつかある
↓
今年フロントエンドを Nuxt.js にリニューアル
↓
管理機能の画面はいまだモノリシックな Rails
※ この物語はお仕事でのお話です
引き継ぎ当時...
🍝
タイトル・改
これからどうする?
ねらいは、メンバーの
スキルアップとテストの充足、
技術負債 🍝 の解消
どことは言いませんが、界隈で有名な
ESM さんにお願いしました。
「テストがないとデグレーションしてしまう!」
「今は機能追加よりもテストやリファクタリングを優先させる」
CEO や他部署に合意してもらい、
技術負債解消ターンに入った
←今ココ
第 1 期:Unit test 系の Spec を充足させる
第 2 期: Integration test 系の Spec を充足させる
↑今ココ
第 3 期:リファクタリング 💪
基本的な自動テストの考え方や RSpec の書き方は
これらを読めば分かる
また、「使えるRSpec入門」シリーズ
なども大変お世話になっている。
の詳しい説明は、
「初めての自動テスト」でも
紹介されています。
我々は model や decorator などの
Unit テストから書いていくことを
「計画づくり」のときに決めた。
「何をテストしたいのか」をペンディングで書いていく
ことにより、頭が整理されるため
describe Article, type: :model do
# テスト対象(メソッド名など)
describe '#published' do
# 状態(〜の場合)
context '非公開記事がある場合' do
# 期待する出力(〜のこと)
it '公開記事のみ取得できること'
end
end
end
describe Article, type: :model do
describe '#published' do
context '非公開記事がある場合' do
before do
create(:article, name: '公開記事', published: true)
create(:article, name: '非公開記事', published: false)
end
subject(:article_published) { Article.published }
# 期待する出力(〜のこと)
it '公開記事のみ取得できること' do
expect(article_published).map(&:published)).to match_array([true])
end
end
end
end
describe Article, type: :model do
describe '#some_data' do
context '何らかのデータがある場合' do
let(:bad_article) { create(:article, title: Foo.title, description: Foo.description, tag_type: 1) }
let(:good_article) { create(:article, title: 'タイトル', description: 'ディスクリプション', tag_type: 'Ruby') }
subject(:bad_some_data) { bad_article.some_data }
subject(:good_some_data) { good_article.some_data }
it 'データの配列が返ってくること' do
# 分かりにくい例 ×
expect(bad_some_data).to eq [article.title, article.description, 1]
# 分かりやすい例 ○
expect(good_some_data).to eq %w(タイトル ディスクリプション Ruby)
end
end
end
end
我々は全知全能だからコードの中身を知っているだけ。
メソッドの中身がどうなっていようと、期待する値を受け取れればそれで良い。
let(:creator) { Admin::DataCreator.new() }
subject(:contract) {
# send を使って private メソッドを呼び出して検証することはできる...
creator.send(:foo, 1, 2, 3)
}
# Table name: users
# ...
# id :bigint not null, primary key
# name :string(255)
# coach_id :bigint
# ...
describe User, type: :model do
describe '.coachs' do
before do
create(:user, name: 'テスト A さん', coach_id: nil)
# 関連するモデルを作れる
create(:user, name: 'テスト B さん', coach: create(:coach))
end
subject(:user_coachs) { User.coachs }
context 'coach を持っているデータが存在する場合' do
it 'coach を持っている user が取得できること' do
expect(user_coachs.count).to eq 1
expect(user_coachs.first.name).to eq 'テスト B さん'
end
end
end
end
describe 'Api::ContactsController', type: :request do
describe '.received_mail' do
subject(:request) {
post '/api/contacts', params: { contact: { name: '太郎', email: 'taro@co.jp', message: 'メッセージです' } }
}
# ...
# リクエストが成功することなどのテスト
# ...
# Api::Mailer.received_mail(Contact.new).deliver
before do
allow(Api::Mailer).to receive_message_chain(:received_mail, :deliver)
.with(instance_of(Contact)).with(no_args)
end
it 'mailer が呼び出されていること' do
request
expect(Api::Mailer).to have_received(:received_mail).once
end
end
describe Foo, type: :service do
describe Foo::Generator do
describe '.call' do
subject(:foo) { Foo::Generator.new }
it 'メッセージが標準出力されること' do
expect { foo.call }.to output("ファイルを出力しました。\n").to_stdout
# .to_stderr で標準エラー出力も検証できる
# expect { foo.call }.to output("エラーが発生しました。\n").to_stderr
expect(File.exist?(file)).to be true
end
end
end
emd
ちなみに...