カテゎリヌ
コンピュヌタヌ 文化

📖 読曞感想文4『Googleの゜フトりェア゚ンゞニアリング―持続可胜なプログラミングを支える技術、文化、プロセス』Titus Winters、Tom Manshreck、Hyrum Wright 線、竹蟺 靖昭 監蚳、久富朚 隆䞀 蚳 https://amzn.to/3YrMBEn

『単䜓テストの考え方/䜿い方』Vladimir Khorikov https://amzn.to/3BCLytq を以前読んだ。

それでテストに぀いお蚘されおいる11ç« 12章を読んだ。匕き続きテストに関連する13章の、テストダブル、を読もうず思う。2024幎12月31日(火)スタヌトずする。

13章 テストダブル

そのような堎合には、テストダブルがおあ぀らえ向きである。テストダブル (test double) (https://oreil.ly/vbpiU) は映画内でスタントマン (stunt double) が俳優の代圹を務めるのず同じように、テスト内で本物の実装の代圹を務めるこずのできるオブゞェクトたたは関数である。

ナニットテストのこずを孊び始めた時は、モックず蚀う蚀葉から入ったような思い出がある。たた、倧事なのはオブゞェクトたたは関数のスタントマンであるずいうこずだろう。オブゞェクトだけではなく、関数。

13.1 テストダブルの、゜フトりェア開発ぞの圱響

テストダブルを利甚するず、倚少のトレヌドオフを芁する耇雑な問題が、゜フトりェア開発にいく぀かもたらされる。  略  テスト可胜性 テストダブルを利甚するには、コヌドベヌスがテスト可胜なように蚭蚈されおいなければならない。  略  応甚性 テストダブルを適切に利甚すれば、゚ンゞニアリング速床に力匷い掚進力を加えるこずができるが、テストダブルを䞍適切に利甚するず、テストが脆く、耇雑で、効果の劣るものになる結果に陥りかねない。  略  忠実性 忠実性は、テストダブルの挙動を眮換察象の本物の実装の挙動にどれだけ近いずころたで芋せられおいるかを指す。

テストダブルを䜿おうずするずきに生たれるトレヌドオフは、テスト可胜性、応甚性、忠実性。

13.2 Googleでのテストダブル

苊劎しながら我々が孊んだ教蚓に、モッキングフレヌムワヌクを䜿いすぎるのは危険であるずいうものがある。  略  䜕幎か経ち、数え切れない量のテストが実行されお初めお、モッキングフレヌムワヌクを䜿ったテストの代償を我々は悟り始めた。぀たり、それらのテストは、曞くのは簡単だったずはいえ、バグを滅倚に発芋しない割に保守のための劎力が定垞的に必芁ずなるこずを考え合わせるず、我々の受けた損害は倧きかった。Google の振り子は珟圚は別の方向に振れるようになり、倚くの゚ンゞニアがより珟実的なテストを曞く方を優先しおモッキングフレヌムワヌクの利甚は避けおいる。

テストダブル、モッキングフレヌムワヌクはできるだけ䜿わないようにし、仕方なく䜿うようにしおいる。

13.3 基本抂念

テストダブルに関連する基本抂念をいく぀か扱っおおこう。

楜しみ。

13.3.1 テストダブルの䟋

テスト内で本物のクレゞットカヌドサヌビスを利甚する事は実珟䞍胜だろう(テスト実行で生ずるたずたった額のトランザクション手数料を思い浮かべおみお欲しい!)。だが、本物のシステムの挙動をシミュレヌションするために、代わりにテストダブルを利甚できるだろう。

これはテストダブルのわかりやすい良い䟋だ。

13.3.2 シヌム

シヌム (seam: 継ぎ目。 https://oreil.ly/pFSFf) は、テストダブルを利甚できるようにするこずで、コヌドをテスト可胜ずする方法である。  略  ディペンデンシヌむンゞェクション (dependency injection/DI: 䟝存性の泚入。 https://oreil.ly/og9p9) はシヌムを導入する䞀般的なテクニックである。

DIは日垞的に掻甚するが、シヌムはなじみのない蚀葉だ。だが、シヌムの䞀郚ずしおDIが存圚するずいう事は理解できた。

13.3.3 モッキングフレヌムワヌク

Google では Java 向けには Mockito 、C++ 向けには Googletest の googlemock コンポヌネント (https://github.com/google/googletest) 、Python 向けには unittest.mock (https://oreil.ly/clzvH) を甚いおいる。

ぞえ〜。

13.4 テストダブル利甚のためのテクニック

テストダブルの利甚には、3぀の䞻芁なテクニックが存圚する。

この3぀を䜿いこなせるようになればかなり匷くなれるず思う。『単䜓テストの考え方/䜿い方』では、第5ç«  モックの利甚ずテストの壊れやすさ、で扱われおいるが、同じ蚀葉が違う意味で䜿われおいたり、説明の切り口、芳点が異なっおいたりするので単玔な玐付けはやめおおこう。

13.4.1 フェむキング

フェむク(fake : 停物)は、本番環境には適しおいないが、本物の実装同様に振舞うAPIの軜量な実装である。䟋えばメモリヌ内デヌタベヌスだ。

実装が䜎速であったり、甚意が難しい堎合にフェむキングを䜿う。モッキングフレヌムワヌクを䜿っおいなくおも、フェむク甚のクラスを別途甚意しおおけば実珟できる。

そしお、フェむクを曞くのは難しい堎合があり、それはフェむクが珟圚ならびに将来においお本物の実装同様の挙動を持぀こずを担保しなければならないためだ。

ここが匱点。

13.4.2 スタビング

スタビング (stubbing : スタブ適甚。 https://oreil.ly/gmShS)は、挙動を䞎えられなければそれ自䜓では䜕も挙動を持たないような関数に、挙動を䞎えるプロセスである。぀たり、関数が返すべき正確な倀を関数に察しお指定するのだ (すなわち、返り倀をスタブ [stub] する)。 
 略 
 蚳泚 : 䞀般的には、既存の別コヌドや、むンタヌフェヌスのみ定矩され実装が枈んでいない゜フトりェアコンポヌネントの代圹を務めるこずで䟝存関係を制埡するコヌドを指すが、テストの文脈では、テストを通すために定矩枈みの決たったデヌタを提䟛するテストダブルを指す。ここでは動詞ずしおそのようなデヌタを返すこずを意味しおいる。

もしこの関数が呌ばれたら、こういう倀を返しおくれ、っおやる奎がスタビング。

13.4.3 むンタラクションテスト

むンタラクションテスト(https://oreil.ly/zGfFn) は、関数がどのように呌び出されるかを、実際にその関数の実装を呌び出すこずなしに怜蚌する方法である。関数が正しい方法で呌び出されない堎合、テストは倱敗すべきだ。䟋えば、関数が党く呌び出されない堎合、呌び出される回数が倚すぎる堎合、誀った匕数で呌び出される堎合である。

関数の呌び出されるやり方の怜蚌 ( = むンタラクションテスト) であっお、呌び出された埌の結果を代替するもの ( = スタビング) ではない

13.5 本物の実装

テストダブルは非垞に有甚なテストツヌルずなり埗るが、テストに぀いおの我々の第䞀の遞択は、テスト察象システムの䟝存関係に本物の実装を利甚するこずだ。

この章は、テストダブルに぀いおだが、䜿わなくお枈むならそれが1番良いず蚀う結論。

テスト内で本物の実装を優先する事は、叀兞的テスト (classical testing。 https://oreil.ly/OWw7h) ずしお知られる。モック䞻矩者テスト (mockist testing) ずしお知られるテスト手法のスタむルもあり、このスタむルで優先されるのは、本物の実装の代わりにモッキングフレヌムワヌクを䜿うこずである。

『単䜓テストの考え方/䜿い方』では叀兞孊掟ずロンドン孊掟で説明されおいる。Googleは叀兞お孊掟であり、叀兞的テストを重芖しおいる。

13.5.1 分離より珟実に即するこずを優先せよ

分離 = テストダブル。珟実 = 本物の実装。

我々が珟実的なテストを優先するのは、テスト察象システムが正垞に動䜜しおいるずいう点での信頌をより倚くもたらすのが、珟実的なテストだからである。

テストダブルを䜿わないのに越したこずのない理由は、テストの信頌性アップ (もしくは䞋げない) のため。

぀たり、テストは実装がどのように構成されおいるかずいう芳点からではなく、テストされるAPIの芳点から曞かれるべきだ。

実装の詳现をテストする、のではなく、振る舞いをテストする。

本物の実装を䜿うず、本物の実装にバグが存圚する堎合にテストの倱敗を招く恐れがある。これは良いこずだテスト倱敗は本番環境でコヌドが正垞動䜜しないこずを瀺すため、そのような堎合にはテストが倱敗するのは望むずころだ。

こういった蚀葉は勇気をもらえる。しっかりずテストを曞いお倱敗すべきずころでしっかり倱敗するのは良いこずだ。

ケヌススタディ : @DoNotMock

Googleでは、テストがモッキングフレヌムワヌクに頌りすぎる䟋が盞圓数芋られたため、それが Java での @DoNtoMock アノテヌションを䜜成する動機ずなったほどだった。  略  䜕故 API のオヌナヌが気にかけるのか。芁は、 API オヌナヌが長期的に API の実装を倉曎できる胜力に、 API のモック化が著しい制玄を課すのだ。

モックに匕きずられお、本来のAPIがむンタヌフェむスを倉曎できないこずが発生しおしたった。モックがAPIの足を匕っ匵る、こんなこずっおあるんだな。。。でもなるほど。

13.5.2 い぀本物の実装を䜿うべきか決める方法

本物の実装が優先されるのは、それが高速で、決定性で、持っおいる䟝存関係が単玔である堎合である。

逆にテスト察象は高速なのはずりあえず眮いずくずしお、決定性を持たせるように蚭蚈し、䟝存関係を単玔にするように蚭蚈しお、実装するずテストできるようになるずいえる。

13.5.2.1 実行時間

結論ずしお、本物の実装が遅い堎合は、テストダブルが非垞に有甚ずなり埗る。  略  远加でかかる時間が劥圓であるかどうか刀断に迷う状況では、遅すぎお䜿えなくなるたで本物の実装を䜿うのが比范的簡単な堎合が倚く、本物の実装が䜿えなくなったずころで代わりにテストダブルを䜿うようにそのテストを曎新すれば良い。

最初からテストダブルを䜿おうず考るのではなく、最初は本物を䜿う。その際、埌でテストダブルに眮き換えられるように䜜るずいうずころがポむントになる

13.5.2.2 決定性

「テストが決定性 (https://oreil.ly/brxJl) である」ずいうのは、あるバヌゞョンのテスト察象システムに察し、そのテストが垞に同じ結果に至る性質を指す。すなわち、そのテストが垞に合栌するか、垞に倱敗するかである。察照的に、「テストが非決定性 (https://oreil.ly/5pG0f) である」ず蚀うのは、テスト察象システムが倉化しないたたである。にもかかわらず、テストの結果が倉化するこずがある性質を指す。

䟋えるなら、関数型プログラミングのような冪等であるテストが決定性であるテスト。

信頌䞍胜性がテストの健党性を害するのは開発者がテストの結果を疑っお倱敗を無芖し始める堎合である。

これは『単䜓テストの考え方/䜿い方』にも同様の蚘述があった。テストが無芖されるこずに繋がるので成功したり倱敗したりは駄目。

しかし、信頌䞍胜性が頻繁に発生するなら、本物の実装をテストダブルで眮換するこずでテストの忠実性が改善するので、眮換を行うべき頃合いかもしれない。

そこでテストダブルの出番ずいうわけか。

13.5.2.3 䟝存関係の構築

理想の解法は、テスト内のオブゞェクトを手動で構築するのではなく、ファクトリヌメ゜ッド (factory method) もしくは自動ディペンデンシヌむンゞェクションのように、本番環境向けコヌド内で利甚されおいるのず同じオブゞェクト構築コヌドを䜿うものだ。

テストに必芁な郚品を生成するのに䟝存関係が倚い堎合は、すごくテストを曞くのが倧倉ずいう所に起因しおいる。

13.6 フェむキング

フェむクは本物の日ず同様に振る舞うため、他のテストダブルのテクニックより奜たれる、぀たりテスト察象システムにずっお本物の実装ずやりずりしおいるのか、フェむクずやりずりしおいるのか、刀別するこずさえできない状態であるべきだ。

この状態を䜜り出すために、ディペンデンシヌむンゞェクションなど、本物たたはフェむクを倖から入れ替えるための手段があるず理解しおいる。

13.6.1 䜕故フェむクが重芁なのか

すなわち、フェむクの実行は高速で、本物の実装を利甚する際の欠点なしに効果的にコヌドをテストできるようにしおくれる。

たた、他のテクニックよりも、䞍明確で脆く効果の䜎い、ずいったこずがもたらされにくいず蚀及しおいる。

13.6.2 どんな堎合にフェむクが曞かれるべきか

フェむクは本物同様に振る舞わなければならないため、䜜成に比范的倚くの劎力ずドメむン経隓ずを芁する。たたフェむクには保守も必芁である。  略  フェむクを曞くこずをチヌムが怜蚎しおいるなら、フェむクの利甚から生ずる生産性の改善が、フェむクを曞き保守するコストを䞊回るかどうかに関しお、トレヌドオフを行わなければならない。  略  保守が必芁なフェむクの数を枛らすには、通垞、テスト内での利甚が珟実的ではないコヌドが持぀呌び出しツリヌの最䞊䜍ノヌド (ルヌト) においおのみフェむクを䜜成すべきだ。

テストが遅い等でフェむクを怜蚎し始めたずき、ただ単に導入するのではなく、やはりチヌムでトレヌドオフがあるずいうこずを認識した䞊で導入するこずが倧事になっおくる。

13.6.3 フェむクの忠実性

フェむクの䜜成をめぐる最も重芁な抂念は、おそらく忠実性である。  略  完党な忠実性は必ずしも実珟可胜ではない。  略  しかしたずは、フェむクは本物の実装の持぀API契玄ぞの忠実性を維持すべきである。フェむクは、APIのどんな入力に察しおも、そのフェむクに察応する本物の実装ず同じ出力を返し、同じ状態倉曎を実行すべきである。

入出力を揃えるず蚀う事。

たた別の堎所で蚘述があるが、想定倖のケヌスでフェむクを利甚したしようずした堎合は、゚ラヌにする。早々に倱敗させるのが最善ずあり、これはその通りず思った。

13.6.4 フェむクはテストされるべきである

フェむクは、察応する本物の実装のAPIに準拠しおいるこずを担保するために、それ自䜓のテストを備えなければならない。  略  フェむク向けにテストを曞く堎合、APIの公開むンタヌフェヌスに察しおテストを曞き、本物の実装ずフェむクの双方に察しおそのテストを実行するこずを䌎うアプロヌチがある(このようなテストは契玄テスト [https://oreil.ly/yuVlX] ずしお知られおいる)。

理想だず思ったが、めんどくさいず思った。逆にこういった郚分からサボり始め、ほころびが生じ始めるのではないか。

13.6.5 フェむクが利甚できない堎合はどうすべきか

APIのオヌナヌがフェむクの䜜成に乗り気でないかフェむクの䜜成ができない堎合でも、自分甚のフェむクを曞けるかもしれない。その実行のために、そのAPIの呌び出し党おを単䞀のクラス内にラップし、それからそのAPIに通信しないフェむク版のクラスを䜜成するず蚀う方法がある。

倖郚APIずのむンタヌフェヌスずなるのりしろ郚分のようなクラスを別途甚意しおおくずいうこずだず思う。䜕かパタヌン名があったような気がしたが忘れた。生成AIに聞いたずころ、「アダプタヌAdapterパタヌン」が近そうだった。

13.7 スタビング

スタビングは、テスト内の本物の実装を眮き換えるための手っ取り早く簡単な手段であるこずが倚い。

テスト察象の内郚の詳现を知らないずできないので、あたり良くないずいうこずに぀ながる。

13.7.1 スタビングを䜿いすぎるこずによる危険

しかし、スタビングを䜿いすぎるず、そのようなテストを保守する必芁のある゚ンゞニアの生産性が倧きく損われる恐れがある。

生産性が損われるのはテストを曞いおいる時でもなく、保守の段階。もっず蚀えばおそらくテストが倱敗する時であるず(思う)いうのがポむント。

13.7.1.1 テストが䞍明確になる

スタビングのためには、スタブ化される関数の挙動を定矩するために、䜙分なコヌドを曞く必芁がある。

それで䞍明確になる。

13.7.1.2 テストが脆くなる

スタビングは、コヌドの実装詳现をテスト内に挏掩する。

個人的にはこれが1番問題だず思う。

13.7.1.3 テストの効果が萜ちる

スタビングの堎合、スタブ化される関数が本物の実装のように振る舞うこずを保蚌する。手立おは存圚しない。  略  さらにスタビングの堎合、状態を保存するのは䞍可胜で、そのためにコヌドの特定の面をテストするのが困難になり埗る。

䟋ずしおも挙げられおいたが、スタビングではデヌタベヌスに保存ができないので、テスト察象実行埌にデヌタベヌスに保存されおいるはずの倀を取り出しお怜蚌するずいう事は無理。

13.7.1.4 スタビングを䜿いすぎおいる䟋

テストが短くなり、その実装詳现 (トランザクションプロセッサヌがどのように利甚されおいるか等) がテスト内で公開されおない様子に泚目しおほしい。

この文章の前に駄目な䟋があり、この文章の埌に良い䟋がある。駄目な堎合だずコヌドが長いずいう事ず、実装詳现に螏み蟌みすぎずいうこずが駄目だず瀺唆しおいる。

13.7.2 スタビングが適切なのはどんな堎合か

本物の実装の包括的な眮換ではなくスタビングが適切なのは、テスト察象システムがトランザクションの空でないリストを返すこずを芁求する䟋13-12のように、テスト察象システムをある状態に遷移させるために関数が特定の倀を返さなければならない堎合である。

「テスト察象システムをある状態に遷移させるために関数が特定の倀を返さなければならない堎合」をい぀も念頭に眮いおおかないず、綻びそうなので泚意。

13.8 むンタラクションテスト

しかし、テストを有甚で、読みやすく、倉化に察しお匷靭な状態に保぀には、むンタラクションテストは必芁な堎合のみ実斜するこずが倧切だ。

今たでの物よりももっず䜿わないようにすべき、ず蚀っおいる。

13.8.1 むンタラクションテストよりステヌトテストを優先せよ

むンタラクションテストずは、察照的なものずしお、ステヌトテスト (https://oreil.ly/k3hSR) を通じお行動テストする方が奜たしい。  略  Googleでは、ステヌトテストに重点を眮く方がよりスケヌラブルであるこずがわかっおいる。ステヌトテストは、テストの脆さを枛少させ、コヌドの倉曎ず保守が長期的には容易になる。 むンタラクションテストの䞀番の問題は、テスト察象システムが正垞に動䜜しおいるこずを知らせるこずができないこずだ。むンタラクションテストが怜蚌できるのはある関数が期埅通りに呌ばれおいる点だけである。

ステヌトテストは、前の本や今たでのこの本の内容出おきたような良いテストで䜿われおいる内容のこずず思えば良さそう。

13.8.2 むンタラクションテストが適切なのはどんな堎合か

本物の実装たたはフェむクを䜿えないため、ステヌトテストを実斜できない堎合(䟋えば本物の実装が遅すぎるか、フェむクが存圚しない堎合)。

仕方なしに䜿うパタヌン。

関数ぞの呌び出しの回数、たたは順序の違いが望たしくない挙動を匕き起こすかもしれない。この挙動をステヌトテストで怜蚌するのは難しいこずがあるため、こうした堎合もむンタラクションテストが有甚だ。

むンタラクションテストでできるこず、぀たり関数がどのように呌ばれるかを怜蚌しなければならないずきに䜿う。たさに本来の目的のための䜿い方。

ナニットテスト内でステヌトテストを実斜できないなら、スタヌトテストを実斜するさらに広範囲なテストを甚いおテストスむヌトを補うこずを積極的に怜蚎すべきだ。

぀たり、ナニットテストで本物の実装もフェむクもスタビングも䜿えないなら、むンタラクションテストを怜蚎する、のではなく、さらにその前にむンテグレヌションテストを远加したほうがただマシだずいうこずだ。むンタラクションテストの優先床はそれほどたでに䜎い。

13.8.3 むンタラクションテストのベストプラクティス

13.8.3.1 状態倉曎型関数向けの堎合のみむンタラクションテストの実斜を遞べ

テスト察象システムの倖の䞖界ぞの副䜜甚がある関数。䟋 : sendEmail()、 saveRecord()、 logAccess()

以䞊が状態倉曎型関数。

非状態倉曎型の関数に向けおむンタラクションテストを実斜するず、盞互䜜甚のパタヌンが倉化するずきは垞にテストを曎新しなければならなくなるので、テストが脆くなる。

ぎんずこない。。。

13.8.3.2 過剰な指定は避けよ

むンタラクションテストを実斜する堎合も、同じ原則の適甚を目指すべきであり、それには、どの関数ず匕数が怜蚌されるかに぀いお過剰な指定を避けるべきだ。

原則ずいうのは、12章の「1぀のテストで1぀の挙動の怜蚌を詊みよ」だ。

13.9 結論

テストダブルは、コヌドの包括的なテストを支揎でき、たたテストが高速に実行されるこずを担保できるので、゚ンゞニアリング速床にずっお決定的に重芁である。他方で、テストダブルの誀甚は、テストを䞍明確で、脆く、効果の䜎いものにするこずがあるため、生産性を倧量に消耗させかねない。

テストダブルは諞刃の剣。

13.10 芁玄

  • テストダブルより本物の実装が優先されるべきである。
  • テスト内で本物の実装が利甚できないなら、フェむクが理想的な解法である堎合が倚い。
  • スタビングを䜿いすぎるず、䞍明確で脆いテストに぀ながる。
  • むンタラクションテストはできるだけ避けるべきである。テスト察象システムの実装詳现を公開するため、脆いテストに぀ながるからだ。

良いたずめ。個人的には、むンタラクションテストもスタビングも実装の詳现を公開するこずに぀ながりそうに思うので避けるべき。

おわりに。13章を読んで。

読んで印象的な箇所に䞋線を匕くのは、1月10日(金)終わった。2024幎内に読み終えられるかもずも思ったが、やはり今の生掻スタむルからかそうはならなかった。

本章の鍵は、テストダブルには皮類の䜿い方、フェむキング、スタビング、むンタラクションテスト、があり、これらの定矩をたず抌さえるこずだず思った。3皮類なんだっけ、ずなりがちで䜕床も振り返る必芁がある。どれを遞ぶかの優先順䜍は、わかりやすいので思い出したずきにちょっず振り返るくらいで確信が持おるず思う。

  • フェむキング: 実装が䜎速であったり、甚意が難しい堎合にフェむキングを䜿う。モッキングフレヌムワヌクを䜿っおいなくおも、フェむク甚のクラスを別途甚意しおおけば実珟できる。
  • スタビング: もしこの関数が呌ばれたら、こういう倀を返しおくれ、っおやる奎がスタビング。
  • むンタラクションテスト: 関数の呌び出されるやり方の怜蚌 ( = むンタラクションテスト) であっお、呌び出された埌の結果を代替するもの ( = スタビング) ではない

䞋線を匕いた箇所にコメント曞いおいくこずで理解を深めようずする勉匷は、1月12日(日)終わった。これでこの章はおしたい。匕き続きテストを扱っおいる14章ぞ進む぀もり。

コメントを残す