『ATDD by Example: A Practical Guide to Acceptance Test-Driven Development』 一人感想戦

『ATDD by Example: A Practical Guide to Acceptance Test-Driven Development』を手に取り読んだ。

一人感想戦をする当人の状況

ATDDについて2021年1月に開催されたJTF2021 Winterで『TDDからATDDへ歩みをすすめる』という発表をするなど、昨年末からATDDに対して本腰入れて実践に取り掛かっている。

ATDDという概念自体はおそらく2・3年前くらいに『実践テスト駆動開発 (Object Oriented SELECTION)』(GOOS本)を通じて知っていたが、当時GOOS本の解説の中で前提とされていたE2EテストとCI実行環境の整備という戦術面にかける時間と優先度がなくて数年間後回しにしていた(結果的に戦術面しか見えていなかったので後回しにした選択は正解だった)。

その後TDDやユニットテストからコード設計・アーキテクチャ設計と流れた先にアジャイル開発を実践していった。そして、イテレーション駆動な開発の流れになっていった先にイテレーションごとの外部品質について戦略を求める自分が降り、その先の一つのプラクティスとして再びATDDが現れた。

Agile Testingというソフトウェアテストの考え方の中でATDDを開発チームに組み込んでいくための理論的根拠・戦略・必要する技術的実装をあれこれ考えた結果をdumpしたのがこの資料となる。

という当人が『ATDD by Example: A Practical Guide to Acceptance Test-Driven Development』を読んだ時にあれこれ思ったことを書き記す。

そして、ここで思ったことを特にそこまで深く思考を巡らせる前にきょんさんはどう解釈したかを聞いていたのがこちらのYouTube配信だった。

ここで出て話も随時反映させていく。

『ATDD by Example』

amazonの書籍紹介概要はこちらである。

With Acceptance Test-Driven Development (ATDD), business customers, testers, and developers can collaborate to produce testable requirements that help them build higher quality software more rapidly. However, ATDD is still widely misunderstood by many practitioners. ATDD by Example is the first practical, entry-level, hands-on guide to implementing and successfully applying it.

『ATDD by Example』という名前はKent Beck氏の『Test-Driven Development By Example』からもじられたもの。

ATDDはAcceptance Test-Driven Developmentである。日本語に訳すと受入テスト駆動開発と訳される。

後で後述するが『TDDとATDD 2021』 という公開雑談イベントの話のきっかけがこの書籍だったので割としっかり目に読んだのだが、土日の空き時間合計3時間程度と月曜日の朝と電車で2時間くらいだったのでおそらく6時間くらいで読めるくらいだった(電子書籍で読んだので物理的な太さはわからない)。

そして、entry-level, hands-on guideとある通り、「まったくやったことがないよ」という人向けに書かれた入門書の位置づけとなる。きょんさんは「30分対面で説明してもわからない人向けには具体的で良い本なのでは」という評価されていた。逆に言うとある程度TDDを知っている人に対しては特にこの本で得られる新たな洞察はそこまでなさそうというところと、ATDDを体系だって説明しきっているわけでもないため、そっと人におすすめしやすい本かというと、そうではないよねぇという感想を抱かれていた。

この書籍は2012年出版ですが、さらに3年前Gojko Adzic氏が『Specification by Example: How Successful Teams Deliver the Right Software』にてATDDを取り上げていた。この書籍との立ち位置の違いを著者はこう述べていた。

- Gojko氏の書籍はadvancedレベルのスキルを持った人向けである
- より初心者が始められるように具体的な方向性を示す

個人的な感想としては、概論として抑えたいことはわかるが取り上げてる例がイマイチに感じてしまった。しかしこのイマイチに感じた一つの理由は前書きを書いているDale Emery氏が次のように述べている。

they describe and implement a small software system—may seem at first glance to be overly simple, or even simplistic. Don’t be fooled by that appearance.

あまりにシンプルにしすぎているように見えるが、多くのことを学べると補足している。実際なぜこうしているのかというチームの振る舞いが丁寧に書かれている。書籍内のいくつかのアイデアはいまいちまだ腑に落ちていないところがあるので一人感想戦を通して言語化していきたい。

Kent Beck氏・Dale Emery氏からのまえがき

この書籍ではKent Beck氏からのまえがきから始まる。同氏はTDDのウィークポイントを、「プログラマのニーズを満たすためのプログラマーのテクニックに陥る可能性があることだ」とまず示す。そして、ATDDはプログラミング言語から少し遠い人たちとのコミュニケーションを強化するテクニックであるという評価をしている。

そして、現在VMWareでソフトウェアエンジニアをされているDale Emery氏もまえがきを寄せている。そこでは顧客の要求をデリバリすることに長年失敗してきたソフトウェアプロジェクトについて述べられていた。開発者は「何を作ることが求められているのか」を注意を払わず、顧客は自分が欲しい物を言わないし知らない。ATDDは開発を始める前段階から「作るもの」に対する理解を共有することが出来ることを強調している。ATDDはJanet Gregory氏とLisa Crispin氏のよる『Agile Testing Condensed: A Brief Introduction』(か『More Agile Testing: Learning Journeys for the Whole Team』ではExample-driven developmentのいちバリエーションであると表現しているが、同氏も具体的な例によってコラボレーションする方法であることを示している。

1. 機能の具体的な例を作る(ためにチームメンバーで協力)
2. 例を自動受け入れテストに翻訳する
3. 例とテストが共有された機能の「done(完成条件)」となる

ATDDの他の語彙たち

2012年当時次のような別語で定義されていたらしい

- Acceptance Test-Driven Development
- Behavior-Driven Development(BDD)
- Specification by Example
- Agile Acceptance Testing
- Story Testing

これについて界隈のテンションはあまりしらないのでぜひ『TDDとATDD 2021』 で話題にしたいが、2019年出版されている『Agile Testing Condensed: A Brief Introduction』を参考にすると上3つはまだ言い伝え続けられている語彙だと思われる。

ATDDについて誤解される点をMichaerl Bolton氏の説明を強調している。

- 受け入れテストが pass したからイテレーションが終わるわけではない
- すべてをテストすることは不可能ということはよく知られている
- 正確には受け入れテストが失敗している場合は終了しない

これさえやればソフトウェアテストとしては大丈夫Vっていうと、テストはそれ以外もたくさんある。Brian Marick氏が初版を出している「アジャイルテストの四象限」においては、ATDDがカバーする分野はQ2だけである点は様々書籍内で言及されている。

画像1

そのため、これも度々引用している『Agile Testing Condensed: A Brief Introduction』の説明を借りてきているが、自動受け入れテストが通った後はそれ以外の探索的テストなども実行する必要性がある。

Specification by Example: How Successful Teams Deliver the Right Software』ではATDDアプローチを実践したチーム50以上をインタビューした結果を公開しているらしいのですが、それぞれのチームが様々なバリエーションのプラクティスを行っていたと話している。最初は基本的なアプローチから始めて徐々に特定コンテキストに合わせて調整していたことを明らかにしている。チームプラクティスとしてそれぞれのチームに合わせて調整していくことは、Agile wayが根底にあるプラクティスとして一つ特徴的な文化背景があるかもしれない。

User Storyの定義

この本のUser Storyの定義があまり個人的には見ない感じの説明で面白かった。

A user story is a limited set of functionality that the team feels comfortable implementing over the course of a single iteration.

一回のイテレーションで comfortable に実装できる機能セット。実際ユーザーストーリーは分割していこうね〜って話が様々な場所で行われていたりするのと、ATDDの説明がUserStoryをベースにして、UserStoryが適切に分割され一回のイテレーションで終わることを前提にしないとその後の説明が難しくなるんだろうなっていう若干著者目線を推察してみたりした。

TesterとProgrammerが協働する具体例(1)

『TDD by Example』と同様に具体例から始まる。最初の具体例は空港の駐車場の価格管理システムである。

この具体例ではそれぞれの料金プランに合わせて時間あたりの駐車料金が違うというビジネスエキスパートの知識を、Business Expert / Programmer / Testerの3人で会話して、具体的な例を見つけていくところから始まる。次のようなテーブル形式で具体例を整理していく。

これを本書では「Specification Workshop」と読んでいる。現在のアジャイル開発のいくつかのプラクティスではスプリントプランニングやバックログリファインメントといった場もそれに該当する点をAgile Testingでは語られていたりする。

 Examples:
 | parking duration   | parking costs |
 | 30 minutes         | $ 2.00        |
 | 1 hour             | $ 2.00        |
 | 3 hours 30 minutes | $ 7.00        |
 | 12 hours 30 minutes| $ 24.00       |
 | 1 day 30 minutes   | $ 25.00       |
 | 1 day 1 hour       | $ 26.00       |

これは2021年周りを見回すとthree Amigosとか呼んでいたりする。

そして、これをCucubmerを用いて自動受け入れテストに起こしていく。書籍内で展開されていった結果のサンプルコードがこちら。

SUT(テスト対象システム)は入力画面を持つためSeleniumを利用、headless Selenium serverの活用によってCIで実行する基盤構成。

Cucumberを用いた場合の事例として次のようなSpecがあげられる。

Feature: Short-Term Parking feature
 The parking lot calculator can calculate costs for Short-Term Parking.
 Scenario Outline: Calculate Short-Term Parking Cost
   When I park my car in the Short-Term Parking Lot for <parking duration>
   Then I will have to pay <parking costs>
 Examples:
 | parking duration   | parking costs |
 | 30 minutes         | $ 2.00        |

Cucumberに限らず受け入れテストの自動化ツールは自然言語で記述するファイルを作成し、その一つ一つのstepに対応する具体的な実装コードを別に用意する。たとえば、gaugeを用いた場合はこういう構造だ。

画像2

この章で特徴的なことは2点で

1. exampleを話し合った後は、テスト作成(by Tester)とプロダクションコード実装(by Programmer)を並走した。

2. 自然言語で書けるSpecとある程度のテストコード実装はTesterがやったが、その後完成させるのはすでにプロダクションコードを書ききった後のProgrammerと協力してテストを完成やった(厳密にはまだSUTに直接アクセスはしないがpauseな受け入れテストは先に書いていた)

というところ。これは『実践テスト駆動開発』で示されていた図を個人的に起こしたものだが、Failした受け入れテストから始めるという構造にはあえてしなかったようだ(そういった例は次の章で取り上げられる)。いちおう受け入れテストを実行して失敗させるところからストーリーは始まっていた。しかし、受け入れテストをステップに対応する実装まで完成させるのはあえて遅延させていた。

画像3

ここで著者が示していたのは、TesterとProgrammerの二人で蜜にコミュニケーションしてお互い得意なことを出し合って仕事していこうというメッセージである。ソフトウェアテスト自動化に不慣れであってもやっていけるんだよ〜っていう応援のニュアンスがとても強い章となっている。

具体例(1)  から〜GUI TestでTest-Firstするか

私が個人的に関心があったのは、UI Testにおいて実装前からSUTへアクセスするステップ実装を書くことに対する効果がどうかという点。デザインが明確に決まっているシステムを実装する場合はその画面要素に対してselectorやidを受け入れテストを最初に書くタイミングで指定すればよいかもしれないが、実装詳細を過剰に規定してしまうリスクが有る。そもそもチェックボックスにするかラジオボタンにするかという段階から実装して顧客フィードバックをもらおうという場合には、Selenium等での画面操作がどうなるかわからない。

しかし、本書の例では並走するという一つのアイデアを提示しており、そのなかでプログラマーとテスターがコミュニケーションをとることで、BusinessExpertとの会話の中で共有したExampleを実現するための詳細仕様について話し自動テストに落としていった。現実的な落とし所としてここかもなぁっておもった。「テストFirst」はしていないが、コミュニケーション技法であるというATDDの目的感は最初のExampleを見つけるワークショップで満たせているし、そのExampleは自動化出来る程度の解像度を得て実際に自動化している。そして「テストFirst」では厳密にはないにしろred-green-refactorのフィードバックループがしっかり回っているのであれば、TDDの意図は満たせているのかも。

ユーザーストーリーのスキルレベルについてAgileAllianceでは述べられている。そして中級レベルのスキルレベルの活用能力として次のように提示している。 

able to express the acceptance criteria for a user story in terms that will be directly usable as an automated acceptance test

こう考えると、いっけん「それは駆動してなくない!!!???」って思ってしまうかもしれないが実はそこまで本質をそらしているわけではないのかもしれないと感じた。

きょんさんとの会話のなかで「どうなっていればTDDしてると感じるか」という話があったが、そこでTDDの生成性について述べていた。

画像7

キョンさんの視点では「駆動」という言葉に囚われすぎていた時代があったという話をしていて、超個体の物理法則における頻繁な正のフィードバックループとゆるい負のフィードバックループが回っている特性をTDDに寄って実現できていることが重要で、そのループを回す最初の入口はテストから入ろうがProductionコードから入ろうがどこからでも良いのでは?という指摘をされていた。ループを自然と生み出している生命体が「ここから始めるんだよねまず」なんて意識しないよねっていう話でたしかにそう...!と思うなどど。

具体例(1)  から〜ハッピーパスから始める

テスト作成時にはまずはハッピーパスから始めるというのは、QA in Agile等において度々話題となる。

先道にそれるが、ちなみに『Clean Agile』では、「ビジネスアナリストはハッピーパス(正常系)を仕様化し、QAはハッピーではないパスを書く。」という整理をしていたりしていた。

『ATDD by Example』においてハッピーパスから始めるべきという論点は、まずUnhappy pathからやってしまうと、UserInterfaceに対する洞察とフィードバックが得られる前から多くの詳細と分岐条件で覆われてしまう点を指摘している。それについてはユーザーストーリーの分割でもハッピーパスとアンハッピーパスを分けるという話はどこかで見たような気がしている。

具体例(1)  から〜ユビキタス言語

three amigosでの会話にて共通認識となるExampleを見つけるには共通の語彙となるユビキタス言語(ubiquitous language)が必要であると指摘する。アジャイルテストの文脈からさかのぼっていってもEric Evans氏にたどり着くのはまぁTDDの文化の生まれがかなりOOPに密接でありDDDがかなりOOPの背景が強いところからそれはそうなんだろうが、ちょっと感慨深かった。

具体例(1)  から〜Collaborationがキーである

これもAgile Testing関連ではよく言われる標語。とくに『More Agile Testing: Learning Journeys for the Whole Team』ではもともとATDD-friendly toolを開発のリズムに入れていたチームが、ビジネスエキスパートとのコラボレーションをするようになって true ATDD となった、というエピソードトークがあるのだが、それに類する話。

具体例(1)  から〜プログラマーが価値を感じるのは実行する瞬間

プログラマーが自動化された例について価値を実感するのは、コードをチェックインする前に手元で動かして確認出来るときだよねっていう話があった。

The programmers eventually find out about the value the automated examples bring them if they execute them before checking in their code to the version control system.

ここで、テスト基盤を作っていくという点ではテストの作成しやすさはTester目線では必要で、一方でプログラマ視点ではテストの実行しやすさが重要であるということがわかる。

テストが実行しやすいようにどの環境で動くSUTに対してもほぼ下準備無しでテストが動かせることが大事だなと改めてね。

ATDDとTDDの入れ子のフィードバックループを作ろうとする具体例(2)

具体例2つ目はより「駆動-driven」身を増し、ATDDがいかにTDDを補完するかという観点でTDDとの組み合わせによる入れ子のフィードバックを解説することを狙ったものとなっている。

題材としてはドイツの信号機システムを実装するという例で、だいたい日本と同じような感じなのでそこまでドイツローカルな感じもないし、その国独自ルールは丁寧に書籍内で解説されている。

構成としてはFitNesseを活用したwiki-baseなテスト定義をしてJavaのテストコードを書き、Javaのプロダクションコードクラスを作るものだ。

私が理解したのはこういう内容だったと記憶している。

画像4

まず、信号機の具体例について共通認識を得るところまでは先程と同じである。そして、そこで得た例をFitNesseでのテストケースにしていく。そしてFitNesseのテストコード実装にてまずSUTはなにも考えずにテストを通す。そしてそこからGlueCodeとしてFitNesseの責務範囲内のJava Classで実際のドメインビジネスコードを書いていく。そのFitNesse責務範囲内のコードにはJUnitでのユニットテストも書いていく。いわばテストコード内でTDDを回す。最後にProduction Codeの責務へクラスを移動するというやりかただ。

正直次の理由であまりしっくり来なかった

1. 受入テスト対象がクラスである事が前提にあるが、テストレイヤとしてシステムに対するブラックボックステストになるのがほとんどでは?
2. このテスト戦略は極めてホワイトボックステストの領域にある同一レイヤ(UnitTest Layer)で二重のテストを作ってない?
3. Component TestレベルはFitNesseにしてUnitTestはJunitにしようみたいな意思決定は当時は納得感があったのかな、現在はそこでツールを分けるということに違和感があった。
4. この前提にはかならず受け入れテストの実装とプロダクションコードの実装は同一言語であるという前提がある(実際そのほうが良いよねっていうのはCucumber等が公式で言っているので別にそこに異論はない)

ぶっちゃけこのしっくりこなさは若干些末な詳細に気を取られて本質を見失っているのかもしれないが、TDDとATDDの入れ子のフィードバックループは正直感じづらかったのが本音なところだった。

実際これについてここでそのままこの話をキョンさんにぶつけた。

まず、TDDでもまずUnitTest内の同一ファイルに「グルーコード」として実装してみて、うまくいったらProductionコードに持っていくことはよく行われる立ち振舞いだが、その振る舞いをそのままこの薄い例でATDDにあてはめるとこうなるという説明がしたかったと思われるという話をされていて「あぁそういうことか」となった。

FitNesseのテストコードの作成とそのフィードバックループを回すのがちょっと重かったりして底に対する開発効率性をあげたい狙いもあるのかもと。

一方で、例としてはチープとなってしまっているので「これをATDDでやる必要あったのかな...?」と思ってしまう読者もいるだろうなと言う話をされていて、「あぁそうそれを思ったんですよ...!」という感じであった。

TDDとATDDが扱う領域が違うことはアジャイルテストの四象限のマッピングがわかりやすいが本書でも次のように言及している。

TDD deals with technical implementations; ATDD deals with acceptance criteria from a business perspective.

画像5

具体例(2)  から〜テストコードの品質

『ATDD by Example』のもう一つの特徴は、テストコードの品質について強い意識がある点。テストコードの品質といえば『xUnit Test Patterns: Refactoring Test Code』(xUTP)が押しも押されぬ書籍として度々参照されるがこの書籍でもよく参照されている。テストの重複を意識して削除したりコードの重複をメソッド抽出等を行うことについてかなり紙面を割いている。IDEを活用することで大きめなリファクタリングも容易になった時代背景をもとにテストコードのリファクタリングについても多く述べている。

Developing test automation code is software development. Therefore, you should apply the same principles to your glue and support code that you apply to developing your production code.

適切なフォーマットを使用すること

具体例での説明が終わると、ATDDの原則などについて話している。そのなかで、適切なフォーマットを使用することを述べていた。

Communicate IntentはxUTPがあげる費用対効果の高いテストの原則の一つである。

そのための適切なフォーマットは画一的なものではなくチームやメンバーによるとしている。そこでは、誰がそのテストを読むのかを意識するべきだと主張している。誰に理解してもらいたいかという点でフォーマットを選択する。Given-When-Thenでなければいけないといったそういうことではないよねっていう話と捉えた。

テストデータとテスト自動化コードの分離

テストデータとテスト自動化コードの分離がATDD-friendlyなテスティングフレームワークの特徴であることを述べている。のちにもあげるがBDDではこういうのをScenario BDDとよぶことがおおいとのことだった。

画像6

自動テストと手動テストのバランシング

自動テストと手動テストのバランスは見極める必要があることを述べている。

Speaking of gaps in your ATDD approach, you have to find the right balance for automating tests versus running manual tests for areas and risks that your automated tests will not cover. Test automation alone leads to an unbalanced approach.

ATDDが属するQ2はテスト分類で見ても自動と手動が入り交じる領域だと整理されている通り、Q1のUnit Test領域と比較してもよりこのバランシングは必要になるだろうなと。

TDDとATDD

さて、冒頭でもあげたがkyonnさんと雑談するきっかけとして最も気になっていたのがここだった。

GOOSが持ち出してるメッセージを中心としたプログラミングとTDDの相性とか色々...。おそらくドメインを育てるという2つ目の例の話に対してだったのかな?特に2つ目はもはやTDDについての解説だった点もありそういうモチベーションで生まれた資料がこちらなのかしらというエスパーをした。実際、書籍を呼んでもう一度この資料を読み返すと完全に二つ目の例の話をしているとわかる!

前半のテストの歴史線の話は付録Cで書かれていてほしい内容だったなって思った。詳しくはこちらで聞いていきたい。

そして聞いた結果はこう

関連書籍

書籍内で度々参照されて後から目を通しておこうと思った書籍をおいておく。



この記事が気に入ったらサポートをしてみませんか?