mokky14's IT diary

IT関係の仕事メモ、勉強会の感想など書いてます。

JaSST'22 Tohokuのレポート

2022/5/27に開催されたJaSST'22 Tohokuのレポート。 今回のテーマはテスト自動化。

今回は現地(盛岡市)とオンラインのハイブリッド開催。自分はオンライン参加。

基調講演 テスト自動化に取り組むにあたり

  • テストピラミッドについて

    • テスト自動化を議論するときよく出てくる
    • テストの量は Unit Tests > Integration Tests > UI Tests となる
      • 各テストの範囲
        1. Unit Tests: Webサーバ、DBサーバ、クライアント(アプリ等)のシステム構成要素内でテスト
        2. Integration Tests: 個々のシステム構成要素を結合したテスト(クライアントーWebサーバ、Webサーバ−DBサーバなど)
        3. UI Tests: システム全体に対するテスト
      • ピラミッドを上に登るほど依存関係が増えていくため、テスト難易度が上がり、実行速度は延びる
      • テスト自動化を進めるときはピラミッドの底(Unit Tests)から取り組むのがお勧め
  • テスト逆ピラミッド

    • テストの量が Unit Tests < Integration Tests < UI Tests となっている構造
    • UI Testsは依存関係が多く、一番時間がかかる
      • このテストで色々なテストを実施しようとするとテスト時間がかかる
  • デモ

    • デモ内容:ブラウザを開き、jasstのサイトにアクセスし、ページ下までスクロールし、上に戻る
    • 実行結果
      • UI Tests 40秒
      • Integration Tests 3秒
        • 速度はサーバ通信に依存する(デモはアメリカから実行)
      • ローカルに置いたWebページのテスト 5ミリ秒
      • Unit Tests 1ミリ秒
    • テスト範囲が大きくなると、テスト時間が大幅に延びる
  • テストの分割方法

    • テストする範囲で分解する
      • ネットワークを境界として区切るのがお勧め
        • デモの例では、jasstサイトアクセスではサーバ側処理、ページスクロールはクライアント側処理
          この範囲で区切るのがお勧め
      • Unit Testsにはnetwork通信自体は含めない。含めるのはIntegration Testsから
    • スコープを限定した実行の素早いコードからスコープの広い遅いコードへ
      • スイスチーズモデル*1のイメージ
      • テストスコープを狭めることで、問題発生時の原因特定も容易になる
  • テスト自動化はテストだけではない

  • これから自動化を学んでいくには

    • 実際のプロジェクトにおいては、使っているツール、言語が異なる
    • これから学ぶ場合、社内の助けを得ることが可能な、社内で使われている技術から始めると良い
    • OSSを活用する
      • OSS開発者にアプローチする
    • 公式ドキュメントから始める

ランチセッション

マウスで描いたグラレコがすごかった。 (著作権とかこわいのでスクショは載せないでおく)

事例紹介

テスト自動化導入後の課題の改善ビフォーアフター

当日の資料 qiita.com

  • テスト自動化業務の6年間で発生した3回の問題とその対応

  • 1 issue

    • 背景
      • 最初は1サービスの1業務だけを担当
        • メンバーが少なく、コミュニケーションも密に取れた
        • テスト自動化のカバレッジも大きくなかった
      • QA組織が大きくなると、複数サービスが対象になり、人も増えた
        • 複数サービスが並行してscriptingを実施
        • テスト自動化のカバレッジも大きくなった
    • 問題
      • お互いのテストが不明確
      • 仕様変更でテスト自動化の失敗が増えた
      • 組織が大きくなると、テスト自動化の役割がさまよう
    • 対策
      • テストの責任範囲・役割を明確に
      • 新規機能・既存機能の仕様変更の明確化と自動化の優先順位付け
        • テスト自動化の範囲を、Project影響外の既存機能+Projectにより修正が加わる既存機能に定めた
        • Project影響範囲のテストは手動テストで実施
  • 2 issue

    • 背景
      • テスト対象のシステムが増えてきた
    • 問題
      • テストの実行キューが溜まるようになってきた
      • いつの間にかテストの実行に時間がかかるようになってきた
        • 全般的にテストが終わらない
      • テストに時間がかかるスクリプトが増えてきた
        • テストデータの肥大化
        • Pipelineの肥大化
        • テストスクリプトがいけてない
      • 問題が起きていることに気がつけなかったのが一番の問題
        • 自動化の内部品質に問題
    • 対策
      • テスト実行結果を可視化し、問題可能性を早期に検出できる仕組みを追加
      • すべての情報をDBに保存するようにした
        • テスト単位で実行時間表示できる機能追加
        • Jenkins単位の実行時間推移を可視化
      • スクリプト単位で実行時間の推移を可視化し、問題があるテストを検出、修正
  • 3 issue

    • 背景
      • 更にテスト対象が増えた
    • 問題
      • 多くのテストが失敗するようになってきた
      • テスト失敗時の運用工数が問題になってきた
        • 自動化テストは、Issueを上げるまでの工数がマニュアルテストより多い
          • 自動化テストで問題が起きると、失敗レポートで原因分析→ローカル実行→バグチケット登録 という作業がいる
        • 失敗したテストを確認した結果、再度実行するとOKになるテストが7割超
          • 一時的なテスト環境の不安定さが原因(スマホ実機をケーブルでつないでテスト実行してる環境なのでおそらく回避不可)
          • いちいちエラー内容確認して再実行するのは非生産的
    • 対策
      • テスト失敗の原因を機械学習させ、再実行した方がよいテストは自動で再実行させるようにした
        • 運用が効率化でき、もっと知的な作業に集中できるようになった

リグレッションテストをほぼ100%自動化した世界

  • MagicPod を使用してテスト自動化した事例

  • 成功したこと

    • ~~ 100%自動化したこと ~~
    • 目的を継続的に達成できたこと
  • 回帰テスト自動化の必要性

  • 目的達成までにやったこと

    • 現状の作業を見つめ直す
      • リグレッションテスト項目から、目的がない・優先度の低いテストを削減
      • 自動テスト以外(ユーザー操作、バッチ操作など)の影響を受けない環境を用意
      • 確認内容が曖昧なテストケースを自動テスト用に置き換え
        • 例) 「ホーム画面が表示されていること」→URLが「https://------」であること
      • プルリクのレビュア、承認者にQAを追加した
  • 回帰テストを100%自動化することで

    • リリース頻度: 月1回→月4回
    • 回帰テストの実行時間: 32時間→2時間
    • テスト結果のフィードバック: 1~3週間 → 2時間~2日
  • 副次効果: 開発者から自動テストの信頼を得られた

    • プルリクが150%増加
      • 以前は複数の修正まとめてプルリクしていた
        • 障害があると、どの修正によるものかの確認から必要だった
          • 開発から日が経ってるため、開発者が修正内容を忘れてることもあった
      • 修正結果へのフィードバックが早く得られるため、開発者が細かい単位でプルリクするようになった
    • リファクタのプルリク数:170%増加
    • 本番障害数0件
      • 今まで手動回帰テスト実施していた時間を別作業に割り当てることができた
    • E2E自動化をきっかけとして、UnitやIntegrationのテストが発達していった
  • 自動テストのテストは絶対にすること

    • テストしないと
      • バグを検知しない
      • 予期せぬ動作をやってしまう
      • 結果が安定しない
  • 成果が出るまでの期間

    • 自動化にかかった期間: 半年間(他の作業)
    • 効果が出るまで: 更に半年

初めての自動化導入は慎重に、計画的に

  • はじまり

    • デグレが度々発生していた
      • 純粋にリソース不足でシステム全体のリグレッションテストが実施できていなかった
    • 手が回っていなかった範囲を自動化しよう
  • 未経験から来る漠然とした不安

    • 原因分析
      • そもそもどこから手を付けてよいのか。。
      • 未経験の分野
      • 「自動化は失敗する」という記事をよく目にする
      • スクリプトはほとんど書いたことない
      • 予算がない
    • 原因掘り下げ
      • どう自動化していけばよいのか分からない
      • 先任者がいないため、始め方のノウハウがない
      • コーディングスキル不足による不安
  • 自動化は小さな一歩から試す

    • 最初から本格的にテスト自動化に取り組むと考えるから壁が高くなる
    • テストに拘らず身近な作業から自動化にチャレンジ
      • RPAツール(Coopel)で自動化を試してみた
      • RPAツールが直感的に使えることもあり、意外と簡単に環境構築作業の自動化に成功。一歩を踏み出せた
        • 手動作成: 30時間 → 自動化: 1.6時間
    • 小さな一歩から成功体験を得ることによって壁が取り除かれた
  • 過去の失敗から学ぶ(アンチパターンの研究)

    • 過去のアンチパターンを見ていると、「未計画で見切り発車することで失敗している」ように思われる
    • 見切り発車しないために
      • 「なにを」「どこまで」テストしないといけないのかという視点
      • 自動化が実現可能かの調査(フィージビリティ調査)
    • 具体的に
      • 「なに」に対して「どのような」検証が必要なのかを検討
      • テスト対象の構成を洗い出して表にする
      • その表に沿って、実際にツールを動かして自動化可能かを調査
    • 実現可能性調査の結果、自動化すべきポイントが見えてきた
    • 副産物としての効果
  • ツールベンダーを活用する

    • ある程度簡単なE2Eであればツールのみで自動化可能だが、複雑な動作検証でスクリプトを使わざるを得ない事態に
      • ベンダーが用意したスニペットを使うことで意外と簡単にできた
  • 不安を一つ一つ解消していくことで色々見えてくる

  • 色々と見えてくれば、次のステップも明確になってくる

ワークショップ

「かま○たちの夜」風のサウンドノベル風ゲームでのワークショップ

ゲーム後の解説ピックアップ

  • すべてのテストを自動化できない
    • ツールがチェックできるのはツールが解釈できる結果のみ
      • データ登録確認などは登録後データでチェックできるが、表示崩れの確認などは困難
    • 探索的テストの自動化はできない
    • 回帰テストは自動化を使用する絶好の機会
  • テスト自動化には初期費用だけではなく固定費もかかる
    • ツール所有コスト
      • ツールのライセンス費用
      • ツールのメンテナンスコスト
      • ツールにより作成された成果物のメンテナンスコスト
      • ツールのトレーニング、メンタリングコスト
    • 別の環境へのツール移植
      • 将来のニーズへのツールの適用
      • ツールを最適に使用するための品質、プロセスの改善
  • テスト自動化の効能
    • 十分に成熟しているテストがすでにあり、そのテストが今後何年も実行される予定がある場合、自動化することでコスト削減できる
    • コスト以外の効能
      • 繰り返し型開発におけるセーフティネットとしての役割
      • バグ修正日数の低減
      • 影響範囲レビュープロセスの代替

ゲーム中のDiscordでのやり取りが面白かったが、個人的に印象に残ったのが、ゲーム中に出てくる上司についてのコメント。

自動化テストの導入に対して、上司理解が得られるかはかなり重要なポイントだと思っているが、自分も含めてみんなここに苦労してるんだなという印象だった。

招待講演 テスト自動化の成功を支えるためのチームと仕組み

当日の資料

speakerdeck.com

  • テスト自動化の成功とは

    • 妥当な対価で目的を達成すること
      • 目的にもレベルがある
        • テスト担当に閉じた目的<チームレベルの目的<ビジネスレベルの目的
        • 自動化の目的を考えるときは広い視点で
      • 自動化による主要な効果
        • テストの有効性の拡大
          • 手動では困難なテストを実施する
          • 本質的な目的達成に貢献する
        • テストの効率性の改善
          • テスト活動にかかる時間やリソースを削減する
          • 同じコストでできるテストを増やす
        • テストの正確性と信頼性の改善
          • 手動のミスを削減する
          • 誤差や不安定さに対応する
        • テストの保守性の改善
          • テストの品質保証、維持、修正、再利用を容易にする
          • テストのインテグリティやトレーサビリティの維持を助ける
      • 主要な対価
        • 必要なリソース(人、物、時間)
        • 必要な労力の種類
          • 自動テストの実現
            • テスト自動化環境の構築・維持
            • 自動化テストの構築・維持
            • テスト自動化に付随する追加作業への対応
          • テスト対象の改善/テストベースの確保
          • 自動化インフラの実現
          • テスト自動化を支えるマネジメントの実現・維持
  • テスト自動化の成功を支える活動

    • テスト自動化を成功させるためには?
      • 適切な目的を立てる
        • 経験的に多いテスト自動化失敗要因:不適切な目的や目標の設定
          • 短期スパンでコスト削減を目標にする→失敗フラグ
            • 中長期スパンで導入を考えないとコスト削減は難しい
        • チームの成功につながる目的を選ぶ
          • テストのニーズ・シーズ・制約・チームの状況に応じて達成できる目的が変わる
          • テスト自動化のリスクや費用対効果が変わる
        • その時のチームにとって有益で実現可能な目的を設定するのが重要
        • 広い活動スコープで目的を設定する
          • テスト担当にスコープを限定するとしょぼい目的になりがち
          • テスト自動化活動のスコープを広げると
            • より本質的・効果的な目的を選択できる
            • 目的達成に使える手段や関係者が増える
        • ステップバイステップで目的達成を目指す
          • テスト自動化活動を継続し、テスト自動化の成功や技術を蓄積すると、より難しい目的に対応できるようになる。
            • 最初は必要な技術レベルが低いものから実施
            • ハードを含むようなテストは必要な技術レベルが高い
      • コストを削減
        • 自動テストにとってのテスタビリティ(テストしやすさ)を高める
          • 品質特性
            • 実行円滑性:円滑に自動化された処理を実行できる
            • 観測容易性:自動テストがテスト対象の出力を観測しやすい
            • 制御容易性:テスト対象の入力を操作しやすい
            • 分解容易性:テスト対象を切り出しやすい
            • 単純性:使用や構造、実行方法が単純
            • 安定性:テスト対象自体のバグや不安定さが少ない
            • 理解容易性:仕様や構造、実行方法が分かりやすい
        • テストの妥当性を高める
          • 価値のあるテストケースを作る
            • ゴミは自動化してもゴミ
        • 自動テストの内部品質を作り込む
          • 拡張性: 少ない対価で自動テストのカバレッジを拡張可能にする
            • モデル駆動テスト → モデルからテストを自動生成
            • データ駆動テスト
            • 環境仮想化
          • 保守コスト悪化によるテスト自動化失敗は多い
        • テスト自動化の計画とアプローチを工夫する
          • 見積もりと戦略策定・計画づくりで、テスト自動化の適切な段取りを構築する。方向づけ・コントロールで段取りの実行を推進する。
            • リソースの選定と確保
            • テスト自動化のリスクのコントロール
          • 段取りの悪さによるテスト自動化失敗が多い
        • 自動テストの活用の頻度と幅を広げる
        • 自動化インフラに自動テストを統合する
          • デプロイメントパイプラインに自動化テストを組み込むことで、自動化テストの責任を果たせる
            • 作っただけだと、適切なタイミングで実行されずに放置されることがある
          • インフラ機能の活用
        • 監視とコントロール、保守で自動テストを維持・改善する
          • 自動テストを保守し、自動テストの効果を維持・改善するよう務める
  • テスト自動化の成功を支えるチームと仕組み

    • テスト自動化の成功要素の実現には、チームと仕組みによる下支えが不可欠
      • チーム
        • 開発とテストがお互いのために連携・協力する体制
      • プロセス
        • 設計段階でもテストを考慮するプロセス
      • 開発インフラ
        • テスタビリティの確認・維持を支えるインフラ
    • テスト自動化を支えるチーム文化
      • チームが文化を誘導する、チーム文化がチームや仕組みを生み出す
    • テスト自動化の成功を支えるチーム文化の志向性
      • チームのテスト自動化の能力を確保し高める
      • Whole Teamでテスト自動化を推進する
      • チームでの自動テストの責務を確立する
      • チームにとっての自動テストの価値を高める
      • チームで自動テストの持続可能性を保つ
      • チームでテスト自動化の動機づけを行う
    • テスト自動化の能力を持つ人材を確保
      • 人材の確保
        • テスト自動化人材のスキルモデルやスキル評価手段の確立
        • 開発能力不足に起因する失敗は多い
      • チーム構築
        • 要となるロール
          • テストアーキテクト:あるべき姿に推進する
          • SET/SETI: 開発技術を活かして、テスト自動化およびテスト自動化インフラに注力
      • チームの能力の維持・向上の仕組み化
    • 自動化インフラの整備
      • デプロイメントパイプラインの自動化
      • 開発インフラで、テスト自動化活動をサポート可能にする
    • テスト自動化のプロセスの整備
      • テスト自動化の良いアプローチや要点をプロセス化してチームに定着させる
        • 能力を伸ばすための学習機会確保
        • プロセス化
        • クライテリア運用
      • テスト自動化の良い習慣の定着
        • コードの読みやすさ(DAMP)
        • Googleのソフトウェアエンジニアリング」は良い本
      • 品質保証・テストの全体設計
      • テスト自動化システムの作り込み
        • テスト自動化システムを整備し、テスト自動化活動を支える
          • テストスクリプトの実装支援
            • GherkinなどのBDDサポート
          • 自動テストを支援するユーティリティ機能の提供
      • チームと仕組みを整備することで、テスト自動化を成功させる活動が容易になる。

当日のプログラムはいじょ

感想など

イベントが終わって

自分が今関わっているプロジェクトはテスト自動化はできておらず、取り組んでいくべきとは考えていた。 テストピラミッドを考えてUnit Testsの自動化から取り組んでいくべきだとは思っていたが、今日の講演を聞いて、そのレベルにもないチームはUI Testsから始めていくのもありかなと思った。

実際、Unit Testを自動化するには、メソッド単位でテストできるような設計・実装が必要で、腐った実装のコードにいきなり導入することはできない。
今のプロジェクトのコードもモンスターメソッドが多数あり、無理やりUnit Test自動化したところで、工数が増えるだけの意味ない作業になるのが目に見えている。
プロジェクトの文化を変えるには、まずは「テスト自動化が有効だ」ということをプロジェクトメンバーに認識してもらわないと先に進めないので、UI Testsから初めてリグレッションテストの改善から取り組むのは有効な手段と思った。

ちなみに、今のプロジェクトでも画面操作リプレイする形式でのUI Testsを試しに導入してみたが、Assertが入っておらずエラー画面に遷移してもテストOKになってしまう程度のもの。 結果、手順を自動化したけど結果の確認は人が行うという事になっていて、導入して何か改善された? というレベルのものになってる。今日の講演で出てきたアンチパターンのオンパレード。 とはいえ、プロジェクトとして「UI Testsを導入してみる」というところは入れているので、目的を整理してここから進めていくのはありかと思った。
テストツールとして、AIがメンテナンスを実施するツールがあるというのも知らなかったので確認してみる。

オンライン開催について

  • PC2台用意して、1台で講演表示+メモを取る、もう一台でDiscordとTwitterを表示しながら参加。
    この参加方法がヒットだった。
  • Discordのコメントへのリアクションが面白い。
    Twitterだとコメントへの反応は「いいね」か返信くらいしかないが、Discordはリアクションのスタンプが多くあり、コメントに対して手軽にリアクションできる。
    他の人と感想を言いあいながら、共感できる事を他の人と共有できるのはオンラインセミナーならではの面白さだった。

現地参加とオンライン参加の方の両方を満足させるのは運営大変だったと思います。ありがとうございました。

関連リンク

JaSST'21 Tohokuのレポート

2021/5/28(金)にオンラインで開催された、JaSST'21 Tohokuのレポート。 今回のテーマはゆもつよメソッド。

例年のJaSST東北は講演+ワークだけど、今回はワーク担当がワークし、ワークの様子を参加者が見るという形での開催。 自分はワーク担当としての参加で、事前ワークの3日含めて参加。 準備した実行委員の方々、本当にお疲れ様でした&ありがとうございました。

ワーク

論理的機能構造図の作成

仕様書をインプットにして、仕様書の内容を機能に分割して「論理的機能構造図」に落とし込む。論理的機能構造図は以下のような図。

f:id:mokky14:20210530021316p:plain
論理的機能構造図

これがゆもつよメソッドの最大の特徴。(多分)
一般的なテストは、システムをブラックボックスとして、ある入力を与えたときの出力を確認する。 このやり方は、システムの内部でどのような事が行われているかを意識しない(できない)ので、必要なテストが漏れる可能性がある。
必要なテストを行うため、内部構造を含めてテスト対象を理解する。 また、機能の構造を理解することで、障害発生時にどこを確認すればよいかを事前に想定できる。

ワーク作成物の例

f:id:mokky14:20210530021440p:plain
ワークで作成した論理的機能構造図(一部)

  • 不明な点があったら「分からないことが分かった」で作業を終了する
    • 「テスト対象を理解する事が目的」なので、仕様書から読み取れない内容は確認する。想像で作らない。
    • この図に当てはめることで、仕様が曖昧になっている箇所が分かる
    • 仕様が明確であればあまり苦労せず作成できる
    • 後で新事実が分かったら戻って見直す
  • まずは、「テスト対象をざっくり理解する」ことが大事

機能一覧の作成

論理的機能構造図に落とした各機能を一覧化し、仕様書のどこに該当機能の記載があるかを反映する。
仕様書は、開発者が実装しやすいように作成していることが多く、テスターがテストしやすいようには作られていないことが多い。 機能に関する記載が仕様書の複数箇所に点在している事があるため、テスト対象の仕様の漏れを防ぎ、後から仕様を確認できるよう、一覧化する。

f:id:mokky14:20210530025138p:plain
ワークで作成した機能一覧(一部)

機能カテゴリは、大きいシステムを対象にした時に分類しやすいように使う。今回の演習は対象アプリが小さいので使用してない。後の成果物では使わないのであまり気にしない。

テストカテゴリの作成

論理的機能構造図のカテゴリ名を、テスト対象に対して開発チームが理解できる言葉にする。 そのまま(入力調整とか)だと分かりづらいので。

f:id:mokky14:20210530030924p:plain
ワークで作成したテストカテゴリ

作業は以下の順で実施する。

  • 前に作成した論理的機能構造図より、各機能で何をするのかを転記する。
  • 各カテゴリ毎に名前をまとめる。
    • カテゴリ毎に1つにまとめられない場合は複数になっても良いが、多すぎるのはNG
      • 細かすぎる名前にはしない!
    • カテゴリ名は「~する」と言って違和感がない名前にするのがよい
    • 貯蔵のところをデータの種類でまとめるのはNG。データが増える度に観点追加になってしまう。

ちなみにワークでは以下の名前にした。

  • 入力調整 → 入力チェック
  • 出力調整 → 表示
  • 変換 → 計算
  • 貯蔵 → データ操作

起こりうる不具合の検討

定義したテストカテゴリのイメージについて、チームメンバー間で認識の齟齬がないように、各テストカテゴリで起こりうる不具合を出し、共通認識を図る。
メンバー間での認識齟齬を防ぐことが目的。書いている内容をメンバー間で合意できればよい。正式ドキュメントにはしない。

f:id:mokky14:20210530031108p:plain
ワークで作成した起こりうる不具合

ワークでの気付き。

  • 不具合は抽象的なものより、ある程度具体化した方がよい
    • 抽象的な内容だと具体性がないため、後で認識違いが出る可能性がある
    • "意識合わせのため"の中間生成物なので、不具合を網羅する必要はない
  • 単体テストレベルの不具合は考えない方がよい

仕様項目の作成

テスト対象の機能ごとに、「何をテストするか」をテストカテゴリ毎で具体化する。

f:id:mokky14:20210530031404p:plain
ワークで作成した仕様項目

注意点とワークでの気付きなど

  • 仕様項目に書くのは「システム」の仕様 (カテゴリに閉じた仕様ではない!)
    • 自分の成果物見たら、検索結果が0件のときの仕様として、データ操作に「データなしの結果を返すこと」と書いていたが、これはデータ操作カテゴリの単体レベルの仕様なのでNG。
    • 単体テストレベルの仕様は書かないよう注意する
      • システムテスト単体テストレベルの確認はやらないので
      • フォーマットがカテゴリ毎になっているため、カテゴリレベルの内容を記載してしまいそうになるので注意する
  • 一つの要件に対する確認方法は一つとする
    • ワークの中で「検索結果が6件以上の場合にページングする」という要件の確認方法として「進む・戻るが動作すること」「各ページに表示されるデータが正しいこと」と記載していたが、2つ目は「検索結果が表示される」という要件に対する確認になる
      • 観点が別であれば分けておき、テスト実施時にまとめられるのであればまとめて実施する
  • システム仕様のレベルでまとめるので、同一仕様を複数カテゴリに入れないようにする
  • テストカテゴリ単位で確認するものがなければ「なし」とする
  • ここまで抽象的に作っていたものを具象化するため、結構混乱する
  • 仕様項目をどれくらい具体的に書くか悩んだ。これは元にする仕様書のレベルに合わせるのがよいかな
  • ワークでやってない「サポート」は自分でやるとき混乱しそうな気がする

ピボットテーブルの作成

作成した仕様項目から、機能とテストカテゴリでどの程度テストを行うかを確認する。 ここで全体のバランスを見て、項目数に違和感がないかを確認する。 バランスが悪いものは仕様項目の粒度が他と合っていない可能性があるので、内容を確認する。

f:id:mokky14:20210530031659p:plain
ピボットテーブル

ワークでは仕様項目は検索機能しか作ってないので、検索だけカウントされてる。 他の機能の「1」は「なし」がカウントされているだけ。

テスト分析はこれで終了。

感想

演習について

  • 具象と抽象の行き来は割と出来た気がする
    • JaSST東北2016でのVSTeP演習で、特定試験のパラメータばかりを深堀りして、全体的な検討をおろそかにした失敗経験が活きた気がする
    • 経験大事
  • 仕様書をベースに成果物を作成するので、開発現場にも導入しやすい気がする
    • ゆもつよメソッド知らない人にも説明ができる
    • テストカテゴリは1回作成したら、同じプロダクトの中では使いまわしていけそう

オンライン開催について

  • マルチモニタ必須
    • Discord、仕様書、ワークの成果物(スプレッドシート、Miro)を開くので、モニタ1台はキツイ
      • 更にtwitterもあったけど、今回は諦め
      • PC2台用意できるなら、そちらの方がよいかも
  • ネットワーク品質、PC スペック大事
    • 当たり前だけど、オンラインなのでネットワークが高速安定してないとキツイ
      • ワークの操作や会話が途切れると集中が切れる
    • DiscordはPCのスペック求められる。共有された画面見てる間、PCのファンがずっと回ってた。
  • 顔出しするか悩んだけど出さなかった
    • Discordは背景変えられないので、後ろの洗濯物とか見えてしまう!
    • 普段の仕事でもオンライン会議で映像は付けてないので、個人的にやりづらさはなかった
  • 19:30からのアフターはムスコからNG出たため参加できず。残念
  • きっと主催者は準備大変だったと思う
    • 本当にお疲れ様でした

現場導入への課題(自分メモ)

自分の前提:開発とQAが分かれておらず、開発者がテストも行う体制

  • どの工程でやるのが適切か?

    • 案件の不明瞭さを確認できるというメリットがあるので、上流工程で実施するのが良さげ
  • どのレベルの規模の案件からやるか?

    • 小規模な案件だと、テスト分析の工数が開発コストに見合わない可能性あり
  • 「ゆもとさん」という神様がいない現場環境での落とし所の調整

    • 意見が分かれたときは判断する人を決めるしかないかな
  • 論理的機能構造図とI /O関連図の住み分け

    • 論理的機能構造図は、開発で作るI/O関連図と内容が一部被ってる
      • 開発する側からすると、同じような内容のドキュメントを複数作らせるのは嫌がられそう
    • I/O関連図と置き換える形で、開発ドキュメントにできるか?

資料など

当日の成果物(チームA)

miro.com

公式ページ

www.jasst.jp

ゆもつよメソッドによるテスト分析の 成り立ちと狙い (JaSST関西2020の資料)

http://jasst.jp/symposium/jasst20kansai/pdf/S5.pdf

ゆもとさんのnote(JaSST'21 Tohoku連動の内容。有料)

note.com

note.com

note.com

note.com

note.com

note.com

note.com

note.com

Togetter

togetter.com

JaSST東北2019のレポート

2019/5/31 JaSST東北2019

書きかけで放置してたのを今更ながら。

2019/5/31のJaSST東北2019のレポート。
今回のテーマは、「基本のキ 明日のテストを楽にする」。

画像は参加者土産のソフトウェアテスト練習帳。
JaSST東北実行委員会が作成した248ページの大作。

f:id:mokky14:20190627063013j:plain
参加者へのおみやげ

基調講演 テスト基本のキ -テストをする前に-

講師: freee) 小山竜治さん

テストの目的と本質の話

  1. 欠陥を摘出する
  2. 対象ソフトウェアの品質レベルが十分であることを確認する
  3. 意思決定のための情報を示す
  4. 欠陥の作り込みを防ぐ

テスト自体はあくまで「知ること」しかできない。
テストにおいて何を知りたいのかを考える必要がある。

  • テストにおいては、何を知りたいのか、誰かが教えてくれるとは限らない。
  • 要求仕様があっても、それが正しいという保証はどこにもない
  • どんな検証システムでも、プログラムが正しいことは証明できない
  • 検証システム自体が正しいという保証もない

JSTQBのテストの7原則より引用

  • テストは欠陥があることは示せるが、欠陥がないことは示せない
  • 全数テストは不可能

SWEBOKのソフトウェアテストの定義より引用

ソフトウェアテスティングとは、通常は無限に大きいと考えられる
「プログラムの振る舞いの実行領域」から
最適だと考えられる有限な「テストケースの集合」を選定し
所期の通りかどうかを実際に動かして検証すること

テストの全量実行は不可能。
何が最適かは、自分で考えて決断する必要がある。

何を知りたいか

知りたいことは目的によって変わる。

目的 知りたいこと
欠陥を摘出する 欠陥がまだありそうか?出なそうか?
対象ソフトウェアの品質レベルが十分であることを確認する 想定した通り動くか
意思決定のための情報を示す 何を知ったのか?
どんなことが起こったのか
欠陥の作り込みを防ぐ ヤバそうなところはどこか

状況や対象によって、目的や知りたいことは変わる。

例えば、1万回に1回落ちるアプリがあったとして、

  • 便利アプリなら?→まあ許容できる
  • 人命に関わるシステムなら?→1万人に1人死亡の可能性あり
  • 経済インパクトが大きいものなら?→1万回に1回訴訟のリスク

SDLC(Software Development Life Cycle)によっても目的が変わる

  • 企画:欠陥の作り込みを防ぐこと
  • 開発:欠陥の摘出
  • 受入:品質レベルの確認
  • 運用:品質レベルの確認

テストすることで知りたいことは何か、まず現状を知って、考える。

テスト対象の分析をする。分析手法はいろいろ VSTePとかマインドマップとか。
テストはアウトプット→思考。まず、自分が知りたいことを考えてみることが必要。
自分で考えてたたき台をアウトプットし、それをみんなで叩いてブラッシュアップして磨きをかける方法がリーズナブル。

freeeで実践しているテスト分析

  • 主なインプットは「会話」と「まとめ」
    • あったら、それにプラスしてドキュメント、チケット
  • できる限りコーダーの時間を割かないように集中して理解して、ドキュメントにアウトプットし、ミーティングで整理する
    • 手段はプロジェクトの対象・メンバー・状況によって変える
    • あまりに情報がない/時間がない場合は探索的テストでテスト実行しながらまとめる
    • 柔軟性が大事

リスクの識別

「知りたいことは?」と言うと色々考えてしまうので、 「何が起きたらヤバイのか」 を考えるのがお勧め。

リスク識別のメリット

  • 早めにフィードバックできる
    • 欠陥が埋め込まれてから摘出されるまでの期間が早ければ早いほど修正コストが低くなる
  • 早めにヤバイところが共有できる
  • ヤバイところがわかるのでテストの方針・計画・戦略が立てやすくなる

リスクの種類には、プロジェクトリスク(プロジェクトの遂行に影響を与えるリスク)とプロダクトリスク(ソフトウェアやシステムで失敗する可能性がある領域)があるが、テスト設計のインプットになるのはプロダクトリスクの方。

リスクを識別・分析するにはテスト対象の分析が必要になる。

  • どのような構造か
    • 構造上ヤバイことになりそうなところは?
  • どのような機能を持つのか
    • 機能上ヤバイことになりそうなところは?
  • どのようなユーザーが使うのか
    • ユーザーにとってヤバイことになりそうなところは?
  • どのような動きをするのか
    • どう動いてしまうとヤバイのか?

リスク分析を行って、それをエンジニアと共有すると、そのリスクが埋め込まれる可能性が減る

テスト技法の必要性の話

リスクはヤバイところから潰す。ヤバイところは早めに潰して安心したい。 テスト終了間際にリスクが高い問題が見つかったらプロジェクトの遅延につながる。

ヤバイからしっかりテストしたい
→ でも全部テストするのは無理。
→ 一番ヤバイところからやりたい。数もいい感じにサンプリングしたい。
有限を選定するためにテスト技法が有用。

テスト対象の何を知りたいかによってテスト技法の使い分けが必要。
テスト技法の使い分けは、秋山さん(@akiyama924)が作成したテスト技法ポジショニングマップが有用。

  • 網羅的に見るのか、ピンポイントに見るのか
  • 構造に着目するのか、仕様に着目するのか
  • シナリオに着目するのか、単機能に着目するのか

まとめ

  • テストにおいては何を知りたいのか 誰かが教えてくれるとは限らない。
    まず現状を知り、考える。
  • テスト対象について、何が起きたらヤバイのかを考えると、「それが起こらないことを知りたい」が出てくる。
  • テスト技法は、無限から最適だと考えられる有限を導き出すテクニック。

事例発表1 テスト自動化プロセスの改善

楽天 江村さん

チームの変遷で直面したテスト自動化の課題

  1. テスト自動化の質を維持するための工数
    1. 「自動化」することが目的に
  2. Manual teamから見て、Automation team が謎
    1. テスト自動化チームが何を担保してるのか分からない
  3. テスト自動化の質が低下
    1. 頻繁なUI改修
    2. テストサイクルが短い

課題を改善する活動

  1. テスト自動化の設計見直し
    1. テスト自動化設計書のテンプレート改善
      • テスト観点、テスト目的を追加した
        • automation teamが何をやっているのか分かるように
      • テスト実施条件の明示
      • 自動化しないことを明示
        • 手動テストの必要性を明確化
      • CI条件を明示
        • CIで繰り返し動作させることを前提に、求められる条件を記載
  2. テスト自動化のレスポンシビリティ

    1. 次プロジェクトまでに自動化
  3. 今後やりたいこと

    • 新規機能も含めてプロジェクト内で自動化カバー
    • マニュアルと自動化の相乗効果向上

事例発表2 テストエンジニア新人研修 心を掴む時間

zozoテクノロジー木村悠

背景 社員5名で品質管理部を急遽スタート(急造チーム 経験不足)

  • モチベーション・マネジメント
    1. 学ぶ心を掴む
      • きっかけを与える
        • 会社が目指していること
        • テストチームが目指していること
        • テストの役割
        • どういった成果につながるか
      • 育成のプロセスとゴールを定める
      • 学ぶ心を掴むための情報を伝える
    2. 楽しむ心を掴む
      1. 最優秀バグの表彰
        1. 月間で不具合レポートから最優秀バグを決定する
          1. 表彰するために、他の人のレポートを見る機会を与える
          2. なぜこのレポートが良いと思ったのか、を表現させる
        2. とにかくバグを見せるべし
    3. 探究心を掴む
      1. 仕様書ベースの試験だけでなく、探索的テスト
        • 試験シナリオをリレー形式で実施
        • Aさんが実施したシナリオを見て、Bさんが次のシナリオ、Cさんが次のシナリオ
        • チームワークで探究心を伝染させる

教える側が焦らないことが大事

  • 表彰されるバグってどんなの?
    • リスクがクローズアップされるものや手順がすごいものなど
    • 単一のポイントで評価はしない
  • 思った通りに成長しない人のフォローは?
    • 人と会話して、その人の長所を伸ばしていくようフォローする

事例発表3 テストの実践力を養うための効果的な技術者教育に関する取り組み事例

町田欣史

  • 問題
    • テスト教育に時間をかけているのに、現場では教育効果が見られない
  • 原因
    • 教え方が悪い、ではなく
    • 研修を開催することが目的になっているから
  • 問題解決の糸口
    • 学生向けに教える
      • 専門用語は使わず簡単な言葉で
      • 身近な事例からテストを考えてもらう
    • 外国人向けに教える
      • 品質に対する意識が低い外国人がテストできるようにしなければならない
        • 人数、レベル、要望に応じて様々な形式で
          • 講義、演習
          • 開発演習
          • マンツーマン
          • 後方支援など
  • 従来の取り組みの改善
    • 相手本位で教育することが最も重要
      • 相手のレベルに合わせて教え方を変える
        • スキルアセスメントを行って、対象者のレベルに合わせて指導
      • 実践に近い演習

当たり前だと思っていることを他人に教えるのは難しい。

感想など

今回は基調講演の内容が非常にしみた。 まとめに内容がまとまってるので再掲。

  • テストにおいては何を知りたいのか 誰かが教えてくれるとは限らない。
    まず現状を知り、考える。
  • テスト対象について、何が起きたらヤバイのかを考えると、「それが起こらないことを知りたい」が出てくる。
  • テスト技法は、無限から最適だと考えられる有限を導き出すテクニック。

最初に考えたテストをすべて実施して、発生したバグは全て対応したのでテスト終わり、ではなくて、 発生したバグの内容から、プロダクトがどういう状態なのか考えるということが大事ということ。
ソフトウェアテストの7原則にあるように、バグがどこかに固まっていることもあるかもしれないし、 テスト方法を変えたら新たな問題が出るかもしれない。
テストを専門にやってる人からしたら当たり前の話かもしれないが、そういう目でバグを見たことがなかったので新鮮だった。

あと、組み合わせテストの演習で使っていたPictMasterを仕事の現場で導入してみた。
最初は「面倒くさい」という若干の拒否反応があったけど、テストやってみたら想定していなかったバグが見つかったりと効果は出ている。
あと、このツールをきっかけに、開発チーム内で「この機能のテスト因子にはどういうものがあるか?」という会話が出てた。ツールで枠組みがある程度決まっているので、その枠の中に入れるべきものは何かという議論に集中できるのだと思う。これもテスト技法の導入効果かと思う。

リンクなど

JaSST'19東北ツイートまとめ - Togetter

www.slideshare.net

www.slideshare.net

Time MachineからMacbookを復元したときの記録

自分が使用しているMacbookが、MacbookのSSDの一部にデータの消失やドライブの故障を引き起こす可能性のある不具合に当たって、Time MachineからOS復元する作業を行った。 復元の際、ハマることがいくつかあったので、備忘として記録を残しておく。

Apple Storeでやったこと

予めTimeMachineで外付けHDDにバックアップを取得した後、Apple StoreMacbookを持ち込んで、問題の有無を確認した。 結果、不具合の可能性があるSSDということで、SSDファームアップデートを実施。 ファームアップデートの後、Macbookは電源を入れても「?」がついたフォルダが表示されるだけで起動できない状態になった。 Apple StoreでOSの再インストールを実施してくれるとの事だったが、復元に1時間くらいかかるということと、TimeMachineのバックアップから復旧すれば問題ないとの事だったので、持ち帰って自分で対応することにした。

Appleストアで聞いた復旧手順

  • command+Rを押したままMacbookの電源を入れる。command+Rは起動するまで押しっぱなしにする。
  • 起動時はネットワークに接続する必要があるので、無線LANにアクセスポイントを選択して接続する、もしくは有線LANに接続する。
  • メニューが表示されたら「TimeMachineから復元」を選択する。

復元作業

外付けHDDを接続した状態で、Command+Rを押しながら電源ボタンを押してMacbook起動した。

ネットワーク接続

  • 自宅の無線LAN(WPA2)は接続しても何も動かなかった
    • ネットワーク選択しても何も動かない場合は、ネットワークを変える必要があるっぽい
  • 有線LANに接続したら、画像のような読み込みが始まった
    • 読み込み途中でゲージが止まって動かなくなることがあった。(5時間くらい放置しても状況変わらず)
      再起動してやりなおしてたら起動した。
      不安定な回線はダメなのかも。(自宅の回線はマンションタイプの光回線で通信が不安定)

f:id:mokky14:20190117041147j:plain

ユーティリティ

言語を選択。

f:id:mokky14:20190204062130j:plain

ユーティリティメニューが表示されるので、「Time Machineバックアップから復元」を選択して「続ける」。

f:id:mokky14:20190204062405j:plain

復元元の外付けHDDを選択。

f:id:mokky14:20190204062634j:plain

復元するバックアップ日時を選択。 続いて、インストール先を選択、、のはずが「ディスクを検索中」表示のまま何も表示されず、先に進めなかった。

f:id:mokky14:20190204063033j:plain

macOSユーティリティに戻って「macOSを再インストール」を選択してみたが、同様にインストール先の選択ができず。 サポートに問い合わせたところ「Option+Command+Rで起動して、OS再インストールしてみて」との事だったので、やってみたがやはりインストール先の選択はできず。

ディスクフォーマット

Mac のディスクを消去する方法 - Apple サポートを見ると、「macOSインストーラでディスクが認識されない」場合はディスクの消去を行う必要があると記載があったので、ディスクの消去を行うことにした。

macOSユーティリティから「ディスクユーティリティ」を起動。

f:id:mokky14:20190204062405j:plain

内蔵ディスクをフォーマットする。手順は以下。

  1. 消去ボタンをクリック
  2. 以下の情報を入力して、消去ボタンをクリック
  3. :名前:任意のHDD名(元のディスク名を入力)
  4. :フォーマット:APFS
  5. :方式:GUIDパーティションマップ

フォーマットしたあと、「再度Time Machineから復元」を実施すると、インストール先のディスクが表示された。

f:id:mokky14:20190204064646j:plain

この後、数時間程度かかって、復元は無事に終了。

f:id:mokky14:20190204064730j:plain

参考

support.apple.com

support.apple.com

TDDBC 8thのレポート

2018/10/20のTDDBC 8thのレポート。

当日のトゥギャッター

t_wadaさんの基調講演

f:id:mokky14:20181024053759p:plain

テスト駆動開発とは

「動作するきれいなコード」がテスト駆動開発のゴール。

「動作するきれいなコード」はいきなり書けない。
まず動作するコードを書き、それからきれいにする。

テスト駆動開発を学ぶのは「テスト駆動開発」を手を動かしながら読むのが近道。

TDDの手順

  1. 作業項目のToDoリストを作る
  2. ToDoで作った項目に対するテストコードを書く
    いきなり全部のテストを作るわけではなく、最初に倒す相手を決める 容易性で決めるのがお勧め
    Javaであれば、パッケージ名、クラス名、ディレクトリ構成など決める必要があり、最初にやることは多い
    タスク自体を簡単にしないと手が止まるので、難易度が高いものは重要であっても後にする
  3. テスト実行して失敗することを確かめる
  4. 目的のコードを書く
  5. テストを成功させる(この時点ではコードは汚いまま)
  6. リファクタリングを行う リファクタリング地獄にならないよう、以下のような条件でを終了する
    • 時間(5分、10分など)でくぎる
    • 重複の除去ができたら完了にする
  7. 次の相手を決めて相手する

ライブコーディング

FizzBuzzをお題にしたライブコーディング。

1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。

ToDoリスト作成
  • 同値分割で考えればいきなり1から100までテストする必要はない。
  • 正しく「プリントする」ことをテストする事は大変だが、そこにロジックはない。
    Viewのテストはコアのテストとは分離する。
  • 「ただし」の前には通常の処理があるはずなので、忘れずにToDo化する

f:id:mokky14:20181024062635p:plain

コーディング

テストコードから書く。

class FizzBuzzTest {
  @Test
  void _1を渡すと文字列1に変換する() throws Exception {
    // 3. 前準備
    FizzBuzz fizzbuzz = new FizzBuzz();
    // 2. 実行
    String actual = fizzbuzz.convert(1);
    // 1. 検証
    assertEquals("1", actual);
  }
}

「数を文字列に変換する」は具体的な値が書かれておらずToDoとして曖昧。 assertは具体的な値でしか書けない。assertを最初に書くことで具体的でなかったという事に気がつく。 ToDoが曖昧であることに気がついたら、ToDoに反映する

テストコードは、検証→実行→前準備と、ゴールから書く。
作ってから使うと、作ったものが使いにくいことに気が付きにくい。 作る前に使うことで、使いやすさを先に検証することができる。

assertのactualとexpectedの指定順はテストフレームワークにより異なるので最初に調べること。

最初はテストコードがfailになることを確認する。 正しくTestコードが実行されてエラーになることを確認する。

プロダクトコードはIDE任せの空実装。 この時点でテストコードを実行し、Redになることを確認する。

class FizzBuzz {
  public String convert(int i) {
    return null;
  }
}

続いてテストをグリーンにするためにコードを修正。

class FizzBuzz {
  public String convert(int i) {
    return "1";
  }
}

グリーンになることを確認する。 ここでテストコードの正当性を確認する。

テストコードのテストは実装コードで行う。 テストコードを実装し、対応するプロダクトコードがまだできていない状況が、一番コストを低くテストコードの正当性を確認できるタイミング。

テストコードをリファクタリングする。

class FizzBuzzTest {
  @Test
  void _1を渡すと文字列1に変換する() throws Exception {
    // 前準備
    FizzBuzz fizzbuzz = new FizzBuzz();
    // 実行 & 検証
    assertEquals("1", fizzbuzz.convert(1));
  }
}

三角測量のコードを書く。

class FizzBuzzTest {
  @Test
  void _1を渡すと文字列1に変換する() throws Exception {
    // 3. 前準備
    FizzBuzz fizzbuzz = new FizzBuzz();
    // 2. 実行 & 検証
    assertEquals("1", fizzbuzz.convert(1));
  }

  @Test
  void _2を渡すと文字列2に変換する() throws Exception {
    // 3. 前準備
    FizzBuzz fizzbuzz = new FizzBuzz();
    // 2. 実行 & 検証
    assertEquals("2", fizzbuzz.convert(2));
  }
}

Redになることを確認したら、プロダクトコードを修正する。

class FizzBuzz {
  public String convert(int i) {
    return String.valueOf(i);
  }
}

Greenになることを確認したらリファクタリング

class FizzBuzz {
  public String convert(int number) {
    return String.valueOf(number);
  }
}

次のテストを追加。

class FizzBuzzTest {
  @Test
  void _1を渡すと文字列1に変換する() throws Exception {
    // 3. 前準備
    FizzBuzz fizzbuzz = new FizzBuzz();
    // 2. 実行 & 検証
    assertEquals("1", fizzbuzz.convert(1));
  }

  @Test
  void _2を渡すと文字列2に変換する() throws Exception {
    // 3. 前準備
    FizzBuzz fizzbuzz = new FizzBuzz();
    // 2. 実行 & 検証
    assertEquals("2", fizzbuzz.convert(2));
  }

  @Test
  void _3を渡すと文字列Fizzに変換する() throws Exception {
    // 3. 前準備
    FizzBuzz fizzbuzz = new FizzBuzz();
    // 2. 実行 & 検証
    assertEquals("Fizz", fizzbuzz.convert(3));
  }
}

テストコード間でコード重複が発生しているので、重複を除去する。 (重複の除去は2アウト派と3アウト派がいる)
重複している前準備のコードを別メソッドに切り出す。

テストコード間に依存関係は作らないこと。 JUnitのテストコードのテストメソッド実行順は上から順になっているわけではない。

class FizzBuzzTest {
  FizzBuzz fizzbuzz;

  @BeforeEach
  void 前準備() {
    fizzbuzz = new FizzBuzz();
  }

  @Test
  void _1を渡すと文字列1に変換する() throws Exception {
    // 2. 実行 & 検証
    assertEquals("1", fizzbuzz.convert(1));
  }

  @Test
  void _2を渡すと文字列2に変換する() throws Exception {
    assertEquals("2", fizzbuzz.convert(2));
  }

  @Test
  void _3を渡すと文字列Fizzに変換する() throws Exception {
    assertEquals("Fizz", fizzbuzz.convert(3));
  }
}

テストコードは具体例だけで、そもそもの仕様が抜けていることが多い。後から見たとき、そもそもの仕様がテストコードから読み取れない事がある。
仕様と具体例をネストして表現するのが良い。(JavaはJUnit5でできるようになった。テストフレームワークによってはできないものがあるかも)

@DisplayName("FizzBuzzクラス")
class FizzBuzzTest {
  FizzBuzz fizzbuzz;

  @BeforeEach
  void 前準備() {
    fizzbuzz = new FizzBuzz();
  }

  @Nested
  class その他の数のときはその数を文字列に変換する {
    @Test
    void _1を渡すと文字列1に変換する() throws Exception {
      assertEquals("1", fizzbuzz.convert(1));
    }

    @Test
    void _2を渡すと文字列2に変換する() throws Exception {
      assertEquals("2", fizzbuzz.convert(2));
    }
  }

  @Nested
  class _3の倍数のときは数の代わりにFizzに変換する {
    @Test
    void _3を渡すと文字列Fizzに変換する() throws Exception {
      assertEquals("Fizz", fizzbuzz.convert(3));
    }
  }

  @Nested
  class _5の倍数のときは数の代わりにBuzzに変換する {
    @Test
    void _5を渡すと文字列Buzzに変換する() throws Exception {
      assertEquals("Buzz", fizzbuzz.convert(5));
    }
  }
}

仕様で分けてみると、1と2の試験をやる意味がないことがわかる。
2のパターンは三角測量のために作ったもので、残しておく意味はないので消す。

「1~100まで」という条件なので、各ケースで最小値と最大値の試験を追加する。

@DisplayName("FizzBuzzクラス")
class FizzBuzzTest {
  FizzBuzz fizzbuzz;

  @BeforeEach
  void 前準備() {
    fizzbuzz = new FizzBuzz();
  }

  @Nested
  class その他の数のときはその数を文字列に変換する {
    @Test
    void _1を渡すと文字列1に変換する() throws Exception {
      assertEquals("1", fizzbuzz.convert(1));
    }

    @Test
    void _98を渡すと文字列98に変換する() throws Exception {
      assertEquals("98", fizzbuzz.convert(98));
    }
  }

  @Nested
  class _3の倍数のときは数の代わりにFizzに変換する {
    @Test
    void _3を渡すと文字列Fizzに変換する() throws Exception {
      assertEquals("Fizz", fizzbuzz.convert(3));
    }

    @Test
    void _99を渡すと文字列Fizzに変換する() throws Exception {
      assertEquals("Fizz", fizzbuzz.convert(99));
    }
  }

  @Nested
  class _5の倍数のときは数の代わりにBuzzに変換する {
    @Test
    void _5を渡すと文字列Buzzに変換する() throws Exception {
      assertEquals("Buzz", fizzbuzz.convert(5));
    }

    @Test
    void _100を渡すと文字列Buzzに変換する() throws Exception {
      assertEquals("Buzz", fizzbuzz.convert(100));
    }
  }
}

ここまでテストケースで表現することで、仕様と具体的なテストケースを表現することができる。
(FizzBuzzになるケースはやってない)

テストコードのメンテナンスについて

f:id:mokky14:20181024060137p:plain

テストコードを実装してきた多くの企業で、過去のテストコードのメンテナンスに時間を取られる状況が発生している。 これからの時代は、テストのメンテナンスコストも考える必要がある。

まとめ

TDDのスキル

  • 問題を小さく分割する
  • 歩幅を調整する
    • テスト → 仮実装 → 三角測量 → 実装 (不安があるうちは歩幅を小さく)
    • テスト → 仮実装 → 実装
    • テスト → 明白な実装 (自信が出てきたら歩幅を大きく)
  • テストの構造とリファクタリング

演習(ペアプロ)

今回のお題。今回のテーマは複素数

今回はC# - MSTestで参加した。
1台のPCを2人で順番に使用するスタイルで実施。

以下、感想。

  • ToDoリストへのフィードバックは行わずに作業していたが、次の作業に進んでよいか、どこまで出来ているかの意識がペア間で曖昧になった。
    どこまで出来たかをペアと意識合わせるためにもToDoで明示するのは大事。

  • コピペでテストケースのメソッド名書いてたら、修正ミスが以外に多かった。
    後々でテスト名だけ見たら何のテストか分からない事になるので注意が必要。
    同じようなコード書くのでテストケースはコピペで実装してしまう事が多いが、コピペは止めた方がよいかも。

  • テストケースのメソッド名に使える文字に制限あるのは辛い。(MSTestの場合) 言語仕様に抵触しないようにメソッド名をどう書くかという、本質でないところで結構悩んだ。

  • Equalsのnull値との比較やGetHashCodeなど、ボイラープレートのコードに対するテストコードを書く必要があるか悩んだ。

    • 悩んだが、プロダクトコードの動作保証としては必要じゃないかと考えたので書いてみた。
    • 開発を進めるためのテストコードと、将来的なメンテナンスを見据えて残すコードは別物と考えた方がいいのかも。
  • コードの「気持ち悪さ」をペアと共有するのは難しい。虚数単位の”i”がコード上に3回出てくるのが気持ち悪いかどうかで意見が合わなかった。

  • 2人が半日で実装したプロダクトコードが50行程度。
    仕事でこんなペースでコード書くのは許されないだろうな、、と思ったりした。

  • レビュー受けたかった。。

コードは当日のペアの方のPCにしかないため、C#の勉強がてら自分で組み直してみた。

GitHub - mokkeee/TDDBC8th

最後に

最近仕事でコード組んでおらす、久しぶりのコーディングだったが楽しかった。 運営の皆さん、演習のお題を考えてくれた@i_takehiroさん、ありがとうございました。

関連書籍など

VAIOのWindows10で無線LAN接続が出来なくなった話

久しぶりにWindows10起動したらWifi接続出来なくなってしばらくハマったのでメモ残しとく。

環境

発生した問題

Windows10を起動したら無線LAN接続が出来ない状態になってた。(以前は接続できてた)
ネットワークとインターネットの設定で、Wi-FiをONにしてもOFFに戻る。

f:id:mokky14:20171029183250p:plain

ここの手順を参考に対応してみたけど状況変わらず。
他に、Windows Updateデバイスドライバの更新やってみたけど状況変わらず。
なお、有線LANは問題なく使えた。

問題原因

VAIOにプレインストールされていたVAIO Smart Networkが原因。
こいつの無線LAN設定がなぜかOFFになってた。

f:id:mokky14:20171029183628j:plain

VAIOコントロールパネルを起動して、VAIO Smart Network→詳細設定を開くと

f:id:mokky14:20171029183639p:plain

無線LANがOffになってた。
ここをOnにして、ネットワークとインターネットの設定のWi-FiをONにしたら無線LAN接続できた。
Offになった理由は分からないけど、どこかのWindows Updateで設定が変更されたのかな?

使ってないツールなのでアンインストールしようとしたら、エラーになってアンインストール出来ず。

f:id:mokky14:20171029184015p:plain

事象が再現する事があるかもしれないので、備忘録として残しておく。

システム設計の原則読書会(2017/8/25)のレポート

2017/8/25のシステム設計の原則 読書会のレポート。 今回は読書会ではなく、著者の増田さんからの執筆裏話+QA。

増田さんの執筆話

www.slideshare.net

個人的に気になったところ。

  • RDRAって初めて聞いたので後で調べる
  • ドメインオブジェクトのパターンは整理しておくと、毎回ゼロベースから考えなくてよいので良さそう
    • 「場所」という感心事に関するLocationパターン
    • 「分類」という感心事に関するCategoryパターン
    • 「権限」「認可」という感心事に関するRoleパターン
  • 現場への取り入れ方が刺さった
    • 現場で結果を形で見せられないと、賛同者も出ない
    • とりあえず自分で手を動かしてみる事を実践してみる
    • 失敗したらそれはそれで財産
  • Kent Beckの言葉
    • どんな状況でも改善はできる
    • どんなときでもあなたから改善を始められる
    • どんなときでも今日から改善を始められる

QA

6章の「データベースの設計とドメインオブジェクト」の内容が気になっていたので質問してみた。

  • 質問
    • ドメインの設計とDBの設計はどのように進めていくのがよいか?
  • 回答

    • まずは、ドメインオブジェクトは業務に着目して設計、DBは事実の記録を行う事だけを考えて進める
    • ドメインオブジェクトを設計していく中で、DBにデータが欲しくなったら、そのときにDBのテーブル等を追加する
      • ドメインオブジェクトの検討の結果として、DBのテーブルが出来る形
      • DBの設計を後に回しても、致命傷になる事は少ない
  • 質問

    • 既にあるDBを使用しなければいけない場合も同じ考え方でよいか?
  • 回答
    • まず「DBを変えてもよいか」を確認する
    • 既存のDBは意識せずに、あるべき理想型のDBを検討する
    • すきあらばDBを変えてしまう

正直なところ、6章の内容は自分でもまだ腹落ちしていない事が多々ある。
実際やったらどうなのか、手を動かして試してみる。