第185回: 「ソフトウェアテストしようぜ」2 庫内スイッチ
◀前の記事へ 次の記事へ▶
≡ はじめに
前回は、「ソフトウェアテストしようぜ」の初回ということで、新連載で何の話を書こうとしているのかについて書きました。
本連載では、毎回、我が家にある何かのテストを勝手に考えます。いつも私が頭の中で妄想していることを書き出すだけです。
「テスターの中には、こんなことを考える人もいるんだー」って思っていただければ幸いです。
一点、注意してほしいことは、「このnoteに書くテストが正解と主張したいわけではない」ということです。(もちろん、「自分ならこんなことをテストしたい」と思う方法を書くわけですが、もっと良い方法があるに違いありません)
かなり小さな、数十行のソフトウェアに対しても無限と言ってもよいくらいのテストケースを考えることができます。また、どんな変に見えるテストケースであっても、「そのテストケースがバグを見つけることは絶対にない」と言いきれる人はどこにもいません。
つい先日も、「壁紙にするとスマホが壊れる画像」が話題になっていました。このように、想像もつかないことが重要不具合の引き金になることもあります。
# もっとも、この壁紙のバグは、プロのテスターなら見つけることができると思うけど。
ということで、毎回、次回のお題を出しますが、本連載は、お題を読んで読者が思いついたテストとの答え合わせではないということです。こんなふうにテストを作る人もいるんだね程度の話です。
さて、今回のお題は、冷蔵庫内の照明を点ける「庫内スイッチ」です。
いらっしゃらないとは思いますが、冷蔵庫の照明が点かなくなったり、ドアの閉め忘れ警告音が鳴りやまなくなってこのページにたどり着いた方がいたら、この先を読んでも何の役にも立ちません。
キッチンのレイアウト変更などで、冷蔵庫の位置を物理的に移動した直後なら、スイッチの配線が外れていないか、そうでなければ、スイッチの押し込み関係を確認してみてください。修理を頼むと1万円くらい取られることもあるみたいです。お見積もりを取るの大事です。
≡ お題(庫内スイッチ)の説明
冷蔵庫は、扉を開くと庫内の照明がつきます。扉を閉めると照明は消えます。前回、以下の仕様を書きました。
扉を閉めるとスイッチ(=キャッチイメージ)が押されることによって、冷蔵庫内の灯りをオフにする
突っ込みどころが多い仕様と思います。例えば、上の仕様には「扉を開くと冷蔵庫内の照明が点灯する」ことすら書いてありません。
形式仕様記述の先生から「この仕様では照明がつきませんね」と叱られそうです。
P → Q (if P then Q、もし P ならば Q が成り立つ)では、PのときにQが成立することしか述べていません。
庫内スイッチの仕様を「P → Q」の形で書くなら、「【扉を閉める】 ならば 【灯りをオフにする】が成り立つ」です。論理包含の関係ですので、【扉を開ける】ときに何が起こるかはこの仕様からは決まりません。
ところが、テストを作るときには、「暗黙の仕様」を考慮すべきと私は考えます。「うちは検証(verification)しかしない契約だから暗黙の仕様はテストしない」という人がいてもいいですが、賛同はしません。「君は、検証しかしないフレンズなんだね」と思うだけです。(古いっ)
前回書いた、
『冷蔵庫を開けっ放しにすると庫内の灯りは消える』ことを思い出すことは大切です。
は、暗黙の仕様の一つです。他にも、
冷蔵庫を開けっ放しにするとピーピーと警告音が鳴る
といったものも暗黙の仕様かもしれません。
個人的には仕様書に明示的に書いておいてほしいですが。
気になる振る舞いの有無が、暗黙の仕様かどうかを確認する方法ですが、テスト結果で「未実装ではないか?」と指摘しても良いです。偽陽性をおそれて仕様書を隅から隅まで確認してから指摘する人がいますが、“自分が変な動きだ”って思ったら遠慮せずに指摘してしまう方が良いです。エンドユーザーもそう思う可能性が高いですし、早く伝われば直るのも早いからです。
テストのときに見つけても時すでに遅しなので、仕様のレビューの際に確認すると良いでしょう。また、テストケースを開発者にレビューしてもらうときに指摘されるかもしれません。
暗黙の仕様については、開発の仕様書をテスターの目線でレビューし指摘するのが理想です。(これをパースペクティブレビューと呼びます)
例えば、こんなふうにレビューのQ&Aで指摘します。
“『冷蔵庫を開けっ放しにすると庫内の灯りは消える』テストのタイムアウト時間の期待値を書けなかったので、何秒でタイムアウトするのか教えてください。”
タイムアウト時に警告音が鳴るかどうかについても同様です。警告音が鳴る場合には、【鳴り始めた警告音がいつ止まるのか】、【警告音と照明が消えるタイミングは同じか】といった、仕様を把握することも大切です。これらは、要求があるにも関わらず、仕様に書かれないことが多いからです。
ちなみに、我が家の冷蔵庫は、「扉を開きっぱなし(タイムアウト1)→警告音がピー・ピー・ピーと3回鳴る→さらに時間が経過する(タイムアウト2)→照明が消える」という振る舞いでした。
≡ テスト対象を理解する
テストを作る前に、テスト対象を理解することが何より大切です。私は、テスト対象の機能をぼんやり考えます。考えるだけではなく自分がテスト対象になった姿を想像します。
今回であれば、冷蔵庫になった自分を想像し、冷蔵庫の気持ちになって、「扉が開いたぞ」、「照明をつけるとともに、タイマーをスタートしよう」なんて考えます。
そうすると、「この情報が足りないからできない」といった機能があることに気が付きます。
今回なら、「1. 照明を点けたり消したりする」、「2. 扉の閉め忘れを感知して照明を消す(警告音も鳴らす)」という二つの機能があるなあ。この2つの機能はどう連動しているんだろう?と考えます。
そして機能と機能をつないだ図(FRAM)を描きます。

この図の見方ですが、六角形は機能を表しています。一番左の「扉」も機能ですが、システム外の人の力を入力して開閉するので(出力しかないので)角丸のラベルの形状となっています。
この図は、FRAM Model Visualiser(FMVと略すことが多い)を使って描きました。
FMVの元データはこちらです。
FMVを使い始めたとき、線の引き方が分からない!って思いました。
画面の左の「側面の記述」のところに、同じものを書くと、線でつながります。(と言葉で書いてもわかりにくいですね。以下のファイルをダウンロードしてFMVで開くとすぐにわかると思います)
機能の頂点の説明は以下の図を参照ください。各機能は、5つの入力(入力I、前提P、資源R、時間T、制御C)と、1つの出力(出力O)からなります。そして、ある機能の出力を別の機能の5つの入力(入力I、前提P、資源R、時間T、制御C)のどれかが受けることによって動作していきます。機能間のつながりは曲線で表現されます。

FRAMについては、例えば以下の書籍に記載があります。
「いつもFRAMモデルを描かないといけないのか?」というと、そんなことはありません。このくらい単純なものならわざわざ描かないと思います。クラス図を全て描くとは限らないのと同じです。
ただし、描いたほうが開発者に質問しやすいですし、描きながら抜け漏れや、機能間のつながりの考察ができます。
例えば、上の図ではタイマー開始のトリガーを「庫内スイッチ」機能としているけれど「電源供給」機能でもよいわけです。
どちらがベターかな? 違うことによってどんなテストが必要かな? と考えます。そもそも「電源供給」機能なんて無いかもしれません。
こうして、ある程度自分で構造を想像してから開発者に「これであっていますか?」と確認を取るようにしています。
※ 昔はFRAMではなく、ラルフチャートを使っていました。でも、ラルフチャートでは、5つの入力(入力I、前提P、資源R、時間T、制御C)の区別が分かりにくいく、開発者に伝わりにくいので、機能間の関係を分析するときには、FRAMを使うようになりました。
モデルは、以下のために書くともいえます。(うまい言い方だなーと思うので、引用です)
モデルを使った分析とは一種のひらめきを喚起するための道具の使用法であるが,ひらめきとは,複数の認知リソースの同時活性化によって生まれるとされているからである
≡ テストを作成する(ステップ1)
私の場合は、2段階に分けてテストを作成しています。
ステップ1では、直感で「これはするだろう」というテストを書き出します。そして、ステップ1で思いついたテストは、「論理的に考えると不要そうに見えても実施する」ことにしています。
(案外、テストでは「直感があたる」から)
今回は、
開け閉めのギリギリを狙う
閉めてからしばらくしたあとも照明が消えていることを確認する
閉じた直後に開く
という3つのテストを思いつきました。
1はUX的な意味です。照明の点き方が自然かどうかを確認したいと思いました。扉が開いたらタイムラグなく庫内が明るくなってほしいからです。扉を閉めるときにも、ギリギリで消灯するようにしてほしいと思います。
2は閉めた後にタイムアウトが誤動作するなどして、扉を閉めるときに消えた照明が再度点いてしまうことはないだろか?という心配事です。
2については、「(バグによって)照明が点いても扉が閉まっているから気づきにくい」こと、「確認に時間がかかる」こと、「そんなバカなことありえない」って思うことから、開発者のユニットテストでは確認していないんじゃないかと思うので、テストしてみたくなります。
2を確認するためには冷蔵庫内にスマホを入れて10分くらい動画を撮る必要があります。テスト用の試験機なら扉に穴をあけてしまってもいいかもしれません。
スマホで動画を撮影しなくても冷蔵庫の消費電力の変化を外からチェックしてもいいけど。
先週のnoteを公開してすぐにリナさんが、「観測容易性(Observability)」のツイートをされていて、マジか!と思いました。
からの連打して
— リナ? (@____rina____) July 9, 2022
満足したら、室内が撮影できるカメラおいてドア閉めるよね
3は、ギューギューに詰め込まれた冷蔵庫で起こりがちなことだから。冷蔵庫内の食品に押し戻されて開いてしまうあれです。(ウチだけじゃないですよね?)
消灯処理の途中で開くと嫌なことが起こりそうって気がするというだけです。
パソコンのシャットダウン中にUSBメモリを抜き差しするとかそんなことからの類推です。
このような、「単に気になるからしたいテスト」って、テストケースに書きたくないし、ひとにお願いするのも気が引けます。
これらをまとめると、ステップ1のテストは経験からピンポイントで狙うテストといえます。
≡ テストを作成する(ステップ2)
こうして、直感でしたいと思うテストのほかに、仕様を網羅するテストも考えます。こちらは、「表」と「裏」を考えます。
■ 表のテスト
まずは、普通に仕様を網羅するテストを作ります。今回でいえば、先に描いたFRAMモデルを利用します。

こちらのモデルには線が6本ありますので、それぞれの線をテストします。制御フローテストのブランチカバレッジ(branch = 枝、coverage = 網羅)と同じです。一つの線に複数のことが書いてあったら、そこは複数のテストになります。
また、タイムアウトのタイマーが適切にリセットされるかといった、過去にあった不具合を思い出しながらテストを作ります。
■ 裏のテスト
裏のテストでは、意地悪な条件を考えます。この図でいえば、庫内スイッチ機能の出力は、タイマー、庫内照明、電力供給の3つの機能のインプットになっています。そこで、出力の順序を変えてみます。
3つの出力先がありますので、順序は3の階乗で6通りです。
また、ハードウェアの故障からの復帰といったソフトウェアにとってイレギュラーな条件について妄想します。
具体的には、照明の電球(LED)が切れて交換したときはタイムアウト後に電球を交換する際に、新しい電球をつけるタイミングで電気は流れているのか?(それともいったん扉を閉じる必要があるのか?)といったテストです。もちろん、瞬間停電のテストもしたいです。
それから、これは、ハードウェアのテストっぽいですが、キャッチイメージのスイッチは手でつまめそうなので、引っ張ってみたいです。(これが、直感によるテストではない理由は、「押す」という行為の反対(対称)から作っているからです。
「間、対称、類推、外側、(破壊)」を思い出しましょう。(忘れちゃった方は『ソフトウェアテスト技法ドリル』を読みましょう。ステマ)。
FRAMでも、「速すぎ、遅すぎ、反転、繰り返し、委譲、割り込み、欠落、順序」等々の「日常と異なる動き」を試すと良いとしています。
以上をまとめると、ステップ2のテストは仕様(モデル)から網羅的におこなうテストです。裏は網羅的に見えないかもしれませんが、テストの経験が増えると、「網羅的に確認しなきゃ」って思うお気に入りの「日常と異なる動き」を持つものです。
≡ 次回のお題
次回のお題はこちらです。

私の部屋の天井についているシーリングライト(照明機器)です。
機能としては、リモコンが分かりやすいと思います。

それぞれのボタンの意味は以下の通りです。
全灯: 一番明るく点灯する(100%点灯モード)
お好みの明るさ: 明暗ボタンで明るさを10段階変化できる(調光モード)
ブルーライト(💡): ブルーライトが点灯する(ブルーライトモード)
消灯: 明かりが消える
明: 明るくなる(明るさは記憶する)
暗: 暗くなる(明るさは記憶する)
です。ブルーライトとはこんなのです。

※ ブルーライトの明るさの強さは変えられません。
≡ おわりに
今回は、「庫内スイッチ」のテストがテーマでした。
「庫内スイッチ」は、単純な押しボタンですが、『案外様々なテストを考えることができるんだなあ』と思われたかと思います。冷蔵庫の扉が両開きだったりすると、もっと複雑になって楽しいですね。
冷蔵庫のテスターは、このnoteの読者にはいらっしゃらないかもしれませんが、ボタンに類するものはたいていのテスト対象にありますので、何かの役に立つかもしれません。
(ちなみに、私は冷蔵庫のテストを仕事でしたことがあります)
次回のシーリングライトのテストは、テスト技法を使うと思います。どの技法を使うか分かるかな? GIHOZにログインしてシーリングライトの仕様をGIHOZのそれぞれの技法(ツール)へ入力してみても良いかもしれません。
