テスト…どう書く??2

こんにちは。株式会社フィックスポイントのよしだです。

今回は、前回に引き続き新入社員が勉強したテスト内容と実際に行ったテストについてご紹介します。

前回の記事は下の通りですので、興味のある方は前編から見てみてくださいね!

blog.fixpoint.co.jp

それでは早速、テストのお勉強の続きから内容に入っていきましょう♪

ペア構成テスト

通常、テストすべき変数の組み合わせは膨大な数になるので、全てテストすることはできません。

そこで、ペア構成テストという技法を用いるのだそうです。

ペア構成テストでは、全ての変数の値の全てのペアをテストします。

これは一般的な経験則による話になるのですが、ペア構成テストを用いると1〜20%のテストで70〜85%の欠陥を検出できるとのことです。

例えば、システムの入力パターンが20個あり、それぞれが10の異なる値を持ちうるとすると、通常組み合わせの数は10の20乗になりますね。

ところが全ての値のペアを網羅するだけなら、180通りで済むため大幅な工数削減となる訳です!

ただ、ペア構成テストにも注意が必要な点があります。

ペア構成テストでは、3つ以上の値の組み合わせをすべて網羅している訳ではないため、特定の重要な組み合わせが漏れてしまうことがあります。

そのことから、以下のようなものは人間の判断で別途テストケースに加えた方がよいのだそうです。

  • 他の組み合わせよりも頻繁に発生する値の組み合わせ
  • 頻度は少なくても、必ず正常に機能しなければならない組み合わせ

ドメイン分析テスト

さて、話は前回の記事に少し戻りますが、同値クラステスト・境界値テストでは独立した変数の値についてテストしました。

しかし、現実問題として以下のような問題があります。

  • システムの全ての変数のために個別にテストケースを作成する時間はない
  • 変数はしばしば相互作用を持つため、個々の変数を独立してテストしていては欠陥は検出できない

そこで、ドメイン分析テストの出番です!

ドメイン分析は、複数の変数を同時にテスト可能且つ、効率的なテストケースを特定できる技法です。

同値クラステストや境界値テストと同様に、境界値が不正確に実装された状況を見つけるのが目的となります。

境界においては、以下のような4種類の欠陥が生じる可能性があります。

そのため、下記のポイントに注意してテストを作成します。

  • on ポイント
    • 境界上の値
  • off ポイント
    • 境界上ではなく、境界に隣接する値
  • in ポイント
    • 全ての境界条件を満たすが、境界上にない値
  • out ポイント
  • 境界が閉じている
    • 境界が等号を含む演算子(≦、≧、=)で定義されている
  • 境界が開いている
    • 境界が統合を含まない演算子(<、>)で定義されている

テストケースの選択法としては、以下の通りです。

  • それぞれの不等号条件に対して、ひとつのon ポイントとひとつのoff ポイントを選択する
  • それぞれの等号条件に対して、ひとつのon ポイントとふたつのoff ポイント(少し大きい値と少し小さい値)を選択する

以上の内容に従って、下の例から制約とテストケースを考えてみましょう。

例
宅配パックの大きさの最大値は、長さ100cm以下、幅100cm以下でかつ長さ・幅の合計が150cm以下です。
また大きさが長さ、幅が共に1cm以上の荷物が宅配の対象となります。

この場合、制約は以下の通りになりますね。

  • 長さ ≧ 1cm
  • 長さ ≦ 100cm
  • 幅 ≧ 1cm
  • 幅 ≦ 100cm
  • 長さ + 幅 ≦ 150cm

制約の整理ができたら、自ずとテストケースを下表のように出すことができます。

長さ 合計 期待される結果
1 任意の on ポイント 任意の on ポイント
0 任意の on ポイント 任意の on ポイント ×
100 任意の on ポイント 任意の on ポイント
101 任意の on ポイント 任意の on ポイント ×
任意の on ポイント 1 任意の on ポイント
任意の on ポイント 0 任意の on ポイント ×
任意の on ポイント 100 任意の on ポイント
任意の on ポイント 101 任意の on ポイント ×
任意の on ポイント 任意の on ポイント 150
任意の on ポイント 任意の on ポイント 151 ×

ここまでで、一度テストに関する勉強が一区切りつきました😌

テストを書いてみよう!

テストに関する知識はつけられたので、あとは実践あるのみです!

発表者は、次のイニシャライザのテストを書くことにしました。

class KCObject:
    def __init__(
        self,
        category: str,
        name: Optional[str] = None,
        key: Optional[int] = None,
        id: Optional[str] = None,
    ) -> None:
        self.__category = category
        self.name = name
        self.key = key
        self.id = id

定義と前提

テスト計画に入る前に、テストを行うにあたっての定義と前提を記載します。

各要素の定義は、以下の通りです。

  • category
    • str
    • action, scope, trigger, ... などの9種類の文字列のうちのひとつ
      • この集合を CATEGORY と呼ぶ
  • name
    • str型 または None
    • 任意の文字列
  • key
    • int型 または None
    • 1~2147483647 の範囲の自然数
  • id
    • str型 または None
    • uuid 形式の文字列

続いて、前提および仮定を以下の通り設定しました。

  • 入力値に異なる型の値が入ることはない
    • 今回のプロジェクトでは mypy を使っているので、型違いは防いでくれるはず
  • 引数が入力されたら正常終了か異常終了する

テスト計画

事前に必要な情報を確認できたところで、テスト計画を立てます。

まず、引数を同値クラスに分類していきます。

category name key id
CATEGORYのいずれかの文字列 任意の文字列 key < 1 uuid形式の文字列
CATEGORYでないいずれかの文字列 None 1<= key <= 2147483647 uuid形式でない文字列
2147483647 < key None
None

上記の通り整理した結果、どうやら境界値テストで十分そうなことが分かりました😊

テストセット作成

テストの技法も選択できたので、いよいよテストセットを作成・実行します!

作成したテストセットは以下の通りです。

category name key id 期待する結果
action any_string 1 5cb6fdf8-964a-47cf-87a1-e5fa4ee3b854 成功
hoge any_string 1 5cb6fdf8-964a-47cf-87a1-e5fa4ee3b854 エラー
action None 1 5cb6fdf8-964a-47cf-87a1-e5fa4ee3b854 成功
action any_string 0 5cb6fdf8-964a-47cf-87a1-e5fa4ee3b854 エラー
action any_string 2147483647 5cb6fdf8-964a-47cf-87a1-e5fa4ee3b854 成功
action any_string 2147483648 5cb6fdf8-964a-47cf-87a1-e5fa4ee3b854 エラー
action any_string None 5cb6fdf8-964a-47cf-87a1-e5fa4ee3b854 成功
action any_string 1 xxxxxxxx エラー
action any_string 1 None 成功

このテストセットでテストを実行した結果、uuid の判定部分に問題があることが判明しました。

つまり、きちんと欠陥が検出できテストを成功させた、という結果を収めることができたのです🎉

おわりに

今回は、前回に引き続き新入社員が勉強したテスト内容と実際に行ったテストについてご紹介しました😌

エンジニアのみなさんが日々勉強を重ね、技術力を高めていることがよく分かる内容だったかと思います。

次回以降の記事でも、弊社エンジニアの伸びしろに期待していてくださいね!





株式会社フィックスポイントでは、一緒に働いてくれるメンバーを募集しています!

詳細は、こちらをご覧ください。