privateメソッドのテストについての考え方 #yochiyochirb
よちよち.rbに久しぶりに参加した。
今日の回はjnchitoさんがゲストとして招かれていて、あれこれ質問できるという会だった。 「昔からよちよち.rbに参加してくれてる人も是非」と言ってもらったので参加させてもらった。
jnchitoさんといえば、今でもRSpecのまとめ記事やRubyの新しいバージョンのまとめ記事はよく拝見するし、 自分がある程度RSpec書けるようになったのは、jnchitoさんらが翻訳された「Everyday Rails - RSpecによるRailsテスト入門」に支えられたところもあり、 お話してみたいと思っていた。
それもあって、最近職場で話して他の人の意見も聞いてみたいと思っていたことを、事前にアンケートフォームから質問として投げた。
#yochiyochirb で伊藤淳一さんに「プライベートメソッドにどうしてもテスト書きたくなっちゃうときないですか?そういうときどうしますか?」という質問をしました。
— うちやま (@highwide) 2019年3月3日
もちろん「書くべきではない」という意見が支配的であることは知っている。 ただし、原則として書くべきでないという前提の上で、それでも書きたくなるケースなどにどうやって対応するのかというのを聞いてみたかった。
事前に、運営をやってくれていたyuki3738さんが、僕の質問を見て「コード例などあるとうれしい」という言葉をくれた。 確かにそのとおりだなぁと思いつつ、そもそも、よちよち.rbに今メインで来ているプログラミングを始めたばかりの方にとっては、「原則として書くべきでない」といったことを前提にするのも不親切かと思い、それならと説明用のスライドを作った。
今日は、それを使いながら質問をさせてもらった。 (他の質問は、運営の方たちがつくった「質問まとめスライド」で済んでいたので、結果的に「自己顕示欲がすごい質問者」みたいになってしまった)
作ってみて思ったが、特定ドメインにしか通用しないようなコードを避けつつ、自分の意図を反映させる、サンプルコードを書くというのは難しいなと気がついた。 技術書とか書いてる人たちすごいなぁ。
いただいたお答えとしては以下のような感じだった。
伊藤さんの答えは「原則書かないほうがいいという大前提のうえで、どうしてもというときは、"これはテストのためにpublic"にしているというコメントの上でpublicにする」だった。 #yochiyochirb
— うちやま (@highwide) 2019年3月3日
加えて「原則書かない方がいいんだから、それを緩和する方針はいずれにせよチームでコンセンサス形成することが大事」ともおっしゃっていたように思う。
一方で、改めて考えると、自分はこういうスタンスだなぁと言語化できた。
時間の中でうまく言語化できなかったけど、自分は「テスタビリティのためにメソッドをpublicにする」っていう"実プログラムの挙動を変えること"の方が、「privateなメソッドをテストコードのみsendで叩く」よりも怖いって思ってることに気がついた。 #yochiyochirb
— うちやま (@highwide) March 3, 2019
このツイートと同様のスタンスの方からリプライいただいたりもした。
もちろん、質問しておいてjnchitoさんからもらった答えを否定したいわけではないし、今日の会でも「自分もpublicにしちゃった」という方はいたので、大事なのはおっしゃるように結局チームでのコンセンサス形成かなって感じもする。
また、懇親会でお聞きした別の興味深かった意見としては「たとえ小さな処理でも、必ずclassに切り出す」というものだ。 その方は、そもそも小さな処理をチェーンしやすくする interactor というgemを勧めていて、小さな処理でも都度classに切り出すことを躊躇していないと言っていた。
Railsなどに依存しない小さなgemでこういう仕組みを使うのはおもしろいと思った。
改めて、今日の運営のyucao24hoursさん/yuki3738さん、会場提供のSansanさん、そしてjnchitoさん、ありがとうございました。
--2019/3/4 0:43追記--
Twitterでtakeshinoda氏とやりとりしていて、スライドのコードに、今回の主旨と関係ない意図せぬダメダメコードがあったことに気がついた...。 スライド12ページ目こうなっていたところ、
# データ加工といってもこの程度ならclass切り出さなくてもいいのでは? data .group_by(&:first) .sort .map { |key, values| [values[0], values[1]] }
意図してたのは、こう書くべきだった。
processed_data = data .group_by(&:first) .sort .map { |key, values| [values[0], values[1]] }
13ページ目も同様に、ここは
data = Hoge::DataAggregator.aggregate process_data(data) Hoge::S3Sender.send(processed_data)
こうしたかった。
data = Hoge::DataAggregator.aggregate processed_data = process_data(data) Hoge::S3Sender.send(processed_data)
スライドを今から修正して上げ直すのはどうなんだ的な感じがするけど、主旨と関係ないところで混乱させるミスなので修正した。
--2019/3/4 1:11追記--
id:sinsoku さんが自分ならこうするというコードをご自身のブログにあげてくれていた。