やわらかテック

興味のあること。業務を通して得られた発見。個人的に試してみたことをアウトプットしています🍵

Rubyの新たなテストフレームワークtldrの紹介

またもやRuby Weeklyで面白そうなgemが紹介されていました。
Ruby製の新たなテストフレームワークtldrというものです。すでにRspecやMinitestが人気を博している中、なぜ新しいテストフレームワークの実装を始めたのでしょうか。気になったので色々と調べつつ、試してみました。
なお、本記事で引用している内容は全て「The TLDR on Ruby's new TLDR testing framework」からの引用です。
tldrの作者であるジャスティンさんが投稿している内容なので、ぜひ合わせてご覧ください。

blog.testdouble.com

tldrのコンセプト

TL;DRは"Too Long, Didn't Read"の略語で、要約を表すスラングです。
このスラングをgem名に採用していることから察するものがありますが、tldrは1.8秒以内にテストが完了しないと爆発してしまいます💣...。
爆発という表現は一般的なテスト失敗(failure)とは異なっており、仮にテストが1.8秒以上を超過してしまった場合には「 your tests didn’t fail, you did.(テストが失敗したではなく、あなたが失敗したのだ)」と考えられています。

your suite crosses the 1.8 second threshold,
your test runner will be staring you in the face telling you that your tests didn’t fail, you did.

以上からも分かるように、tldrでは遅いテストの構築を阻止するということに重きが置かれています。
1.8秒がどういった基準で決定された数値なのかは分かりませんでしたが、この閾値は変更することができません。
tldrを使用する以上、ユーザーは必ず1.8秒以内に実行が完了するテストを書くことを強いられるのです。
個人的には自由度を減らして、堅牢なコードを作り上げるための素晴らしい制約だと思います。

tldrが生まれた背景

一昔前はテストを書くことが、今ほど一般的ではありませんでした。
しかし、今日ではテストを書くことは多くの開発者にとって当たり前のことになりました。その過程にはTDD(テスト駆動開発)やテストフレームワークの普及が一役を担っているでしょう。
しかし、多くの開発者がテストを書くようになったことでテストの量が膨大となり、全てのテストを完了させるのに膨大な時間がかかるようになりました。実際に、自分の開発現場でも並列実行をしているにも関わらず、全てのテストが完了するのに10分程度はかかっています。
開発者としてはテストの完了を10分も待たないといけないのは非常にストレスです。何とかならないものか...。

tl;dr,
Running some of your tests frequently is better than running all of your tests infrequently
全てのテストを頻繁に実行するよりも、一部のテストを頻繁に実行する方が良い

この問題に対して作者のジャスティンさんが言うには「一部のテストを頻繁に実行する方が良い」そうです。
必ずしも高速なテストが良いという訳ではなく、高速なフィードバックによって開発の生産性は高まります。またCIの料金を抑えることができるという点にも触れられています。

まとめると...

  • テストを書くことが一般的になった
  • その代償として、テストの量が増えまくってしまった
  • 結果、実行時間が肥大化してしまい、生産性の低下を招いている
  • これからは高速なテストを書いて生産性を上げていこうよ

テストを高速に実行するために、tldrはデフォルトで並列にテストを実行してくれます。
しかもランダムな順序で実行するため、仮に実行順序が変化することで期待値が変わってしまうテストがあれば、この時点で発見することが可能となるかもしれません。

A no-nonsense CLI that runs your tests in random order and in parallel by default (modern machines have so many CPU cores, it really cooks! 🔥)

試してみる

github.com

いつもは試した結果を紹介するだけなのですが、tldrはコンセプト・背景が面白かったので前談が長くなりました。
READMEを元に簡単なテストを書いてみました。bundle経由でtldrがインストール済みです。

test/sample_test.rb

# frozen_string_literal: true

require 'tldr'

class MathTest < TLDR
  def test_adding
    assert_equal 1 + 1, 2
  end
end

書いたテストを実行してみます。

$ bundle exec tldr
Command: bundle exec tldr 
🌱 --seed 6331

🏃 Running:

😁

Finished in 0ms.

実行がとにかく早いです。シンプルなテストではありますが、あっという間に実行が完了しました。
fswatchというコマンドをインストールしておく必要がありますが、対象ファイルをウォッチして変更があればテストを自動で実行させることもできます。Rspecでも同じことが可能ですが、tldrでは標準機能として提供されています。

github.com

$ bundle exec tldr --watch test/sampleest.rb 

爆発させてみる

sleepを使って意図的に1.8秒以上、テストの実効時間を確保してみます。
さてドキュメント通り、爆発してくれるのでしょうか...。

test/sample_test.rb

# frozen_string_literal: true

require 'tldr'

class MathTest < TLDR
  def test_adding
    sleep 2
    assert_equal 1 + 1, 2
  end
end
$ bundle exec tldr
 $ bundle exec tldr
Command: bundle exec tldr 
🌱 --seed 3097

🏃 Running:

🥵

🚨==================== ABORTED RUN ====================🚨

too long; didn't run!

🏃 Completed 0 of 1 tests (0%) before running out of time.

🙅 1 test was cancelled in progress:
  1805ms - MathTest#test_adding [test/sample_test.rb:6]

🤘 Run the 1 test that didn't finish:
  bundle exec tldr  "test/sample_test.rb:6"


🙈 Suppress this summary with --yes-i-know

🚨==================== ABORTED RUN ====================🚨

Finished in 1806ms.

0 test classes, 0 test methods, 0 failures, 0 errors, 0 skips

無事(?)に爆発してくれました。
記載の通り1.8秒以上、実行時間が必要なテストを許してくれませんでした。

文法・機能などについて

Minitestと互換性がありassert, assert_equalを中心にテストを構築していくようです。
自分はRspec派なので、仮に移行しようとすると大変そうです。今後、何かしらの形でサポートされるかもしれません...。
READMEを見ただけで簡単なテストが書けたので、使い方を覚えるに苦労することはないでしょう。
test_helper.rbを利用したり、デフォルト値をyamlファイルに登録できたりとRubyで人気のあるテストフレームワークと近しいことがすでにサポートされています。約1ヶ月前から開発が始まったようなので、恐ろしい実装スピードです...。

最後に

Ruby製の新しいテストフレームワークtldrについて簡単に紹介しました。
何よりもコンセプトが面白くて「1.8秒以内に終了できないテストはテストが失敗したのではなく、あなたが失敗したのだ...」という考え方には確かになと思わされました。
並列で実行されるため、実行速度も早くなりそうですし、提供されているメソッドもシンプルです。
もし新しいプロジェクトを開始するのであればtldrを検討したいと思いますが、既存のRspecで山のように書かれたテストを移行するのは骨が折れそうです。

Googleトレンドでの判断にはなりますが、Rubyのテストフレームワークで最も人気を得ているのはRspecのようです。 今後、Rspecとの互換性をどのように担保するのかは大きな課題になるでしょう。

少しでも「ええな〜」と思ったらはてなスター・はてなブックマーク・シェアを頂けると励みになります。