PICTを使ってみませんか？

# PICTを使ってみませんか？

## はじめに

こんにちは！株式会社BTMの関口と申します。
業務を行っていくにあたって、テストについて調べていたのですが、PICTという便利なツールの存在を知りました。
ここではPICTについて紹介させていただきます。

## PICTとは

PICTとは、組み合わせのテストケースを自動生成するMicrosoft製のCLIツールです。
テスト対象に、例えば入力項目等が複数あった場合、組み合わせによりテストケースが膨大な数になってしまった、ということがよくあると思います。
そんなときにPICTを使うことで、手動で作成するよりも効果的かつ効率的な組み合わせのテストケースを作成することができます。
PICTという名前は「Pairwise Independent Combinatorial Testing」の頭文字で、ペアワイズ法というテスト技法を使用したツールになっています。

## ペアワイズ法とは

ペアワイズ法とは、ソフトウェアのほとんどのバグは、1つの要素、あるいは2つの要素が組み合わさったときに生じているという仮説に基づいて、要素間の各ペアを網羅するテストケースを作成するテスト技法です。
全ての組み合わせを試さなくてよいので、テストの効果を保ちながらも、テストケースを減らすことが出来ます。

## インストール

ここでは、Ubuntu(WSL2)、 MacOSでの方法を示します。
なお、私の動作環境のOS及びPICTのバージョンは以下の通りです。

|            |version     |
|------------|------------|
|Ubuntu(WSL2)| 22.04.5 LTS|
|MacOS       | Sonoma 14.5|
|PICT        | 3.7.4      |


### Ubuntu（WSL2）

```bash
# 必要なライブラリ等をインストール
$ sudo apt-get install clang libc++-dev

# ソースをクローンして、コンパイル、インストール
$ git clone https://github.com/Microsoft/pict.git
$ cd pict/
$ make
$ sudo install -m 0755 pict /usr/local/bin/pict
```

### MacOS

```bash
# 上記とほぼ同様
$ git clone https://github.com/Microsoft/pict.git
$ cd pict/
$ make
$ sudo install -m 0755 pict /usr/local/bin/pict
```

ターミナルで以下のように実行・表示されればOKです。

```text
$ pict
Pairwise Independent Combinatorial Testing

Usage: pict model [options]

Options:
 /o:N|max         - Order of combinations (default: 2)
 /d:C             - Separator for values  (default: ,)
 /a:C             - Separator for aliases (default: |)
 /n:C             - Negative value prefix (default: ~)
 /e:file          - File with seeding rows
 /r[:N]           - Randomize generation, N - seed
 /f[:text|json]   - Output format (default: text)
 /c               - Case-sensitive model evaluation
 /s               - Show model statistics
```

## シンプルな使い方

まずは最もシンプルな使い方から始めたいと思います。
ここでは、Webアプリを正常に使用できるかどうかのテストケースを作成したいとします。
Webアプリの実行環境の要素をクライアントのOS、ブラウザ、Webサーバー、サーバーOSとし、それぞれの値を以下のようにしました。

```text
ClientOS: Ubuntu, CentOS, MacOS, Windows
Browser: Chrome, FireFox, Edge
WebServer: NGINX, Apache
ServerOS: Ubuntu, CentOS, RHEL, Windows
```

仮にこの全てをテストする場合、4 × 3 × 2 × 4 = 96通りのケースが必要となります。
これを、実際にPICTを使ってテストケースを作成してみたいと思います。

上記で示した内容を以下のようにinput.txtに記載します。

input.txt

```text
ClientOS: Ubuntu, CentOS, MacOS, Windows
Browser: Chrome, FireFox, Edge
WebServer: NGINX, Apache
ServerOS: Ubuntu, CentOS, RHEL, Windows
```

inputファイルの書式は以下の通りです。

```text
<項目名>: <値1>, <値2>, <値3>, ....
<項目名>: <値1>, <値2>, <値3>, ....
<項目名>: <値1>, <値2>, <値3>, ....
```

input.txtが作成できたら、以下のコマンドで実行します。

```bash
$ pict input.txt
```

実行すると、以下のように出力されます。

```text
ClientOS    Browser     WebServer   ServerOS
Windows     Chrome      Apache      CentOS
CentOS      Chrome      NGINX       RHEL
MacOS       FireFox     NGINX       Ubuntu
Windows     Edge        Apache      Ubuntu
Windows     FireFox     Apache      RHEL
Ubuntu      Edge        NGINX       Windows
Ubuntu      Chrome      Apache      Ubuntu
MacOS       Chrome      Apache      Windows
MacOS       Edge        NGINX       CentOS
CentOS      FireFox     Apache      Windows
CentOS      FireFox     NGINX       CentOS
Windows     Edge        NGINX       Windows
Ubuntu      FireFox     NGINX       CentOS
Ubuntu      Edge        NGINX       RHEL
MacOS       FireFox     NGINX       RHEL
CentOS      Edge        NGINX       Ubuntu
```

最初の行が各要素を示したヘッダーとなっています。
2行目以降が実際に生成されたテストケースです。
出力件数は16件となっていて、テストケースを大幅に減らすことができました。

:::note info
もちろん、ただ減らしただけではありません。このケースの中で、それぞれの要素が必ず一度はペアになっています。
:::


## PICTで出来ること

PICTには、より効果的かつ効率的なテストケースを作成するための様々な機能が備わっています。
以下にどのようなことが出来るか、主な機能の概要を示しておきます。

| 機能名       | 概要                                                                                                                               |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| 条件付き制約 | if文で指定した条件が成立した場合に、テストケース生成ルールに制約を設ける                                                           |
| 無条件制約   | テストケース生成ルールに対して、常に有効な制約を設ける                                                                             |
| サブモデル   | 項目をグルーピングすることで、グループに適した組み合わせ数を設ける                                                                 |
| エイリアス   | 複数の値を同値として扱い、テストケースを作成する                                                                                   |
| 無効値テスト | テストを失敗させる二つ以上の値が組み合わさらないように設定する                                                                     |
| 重み付け     | 値に対して重み付けを行い、テストケースへの出現数を調整する                                                                         |
| 原型ファイル | PICTの出力結果と同じ形式のファイルを渡すことで、既存のテスト結果にテストケースを追加したり、必ず出現させたいテストケースを指定する |

本記事ではエイリアス機能を紹介したいと思います。

## エイリアス

エイリアスを使用すると、同等と思われる複数の値に同じ名前が割り当てられ、同値クラスとして扱うことができるようになります。

例えば、以下のようなケースを考えてみたいと思います。

```text
ClientOS: Ubuntu, Kubuntu, Xubuntu, Lubuntu, CentOS, MacOS, Windows
Browser: Chrome, FireFox, Edge
WebServer: NGINX, Apache
ServerOS: Ubuntu, CentOS
```

いわゆるUbuntuフレーバーと言われるOSを追加しました。
このような場合に、"|"記号を使用することで、UbuntuフレーバーのOSをUbuntuと同値として扱うことができます。

```text
ClientOS: Ubuntu | Kubuntu | Xubuntu | Lubuntu, CentOS, MacOS, Windows
Browser: Chrome, FireFox, Edge
WebServer: NGINX, Apache
ServerOS: Ubuntu, CentOS
```

実際に試した結果が以下になります。

#### エイリアスなし

| ClientOS | Browser | WebServer | ServerOS |
| -------- | ------- | --------- | -------- |
| Xubuntu  | Chrome  | Apache    | Ubuntu   |
| Lubuntu  | Edge    | NGINX     | Ubuntu   |
| CentOS   | Edge    | NGINX     | CentOS   |
| MacOS    | Chrome  | Apache    | CentOS   |
| Ubuntu   | Chrome  | Apache    | CentOS   |
| Windows  | Chrome  | Apache    | Ubuntu   |
| Kubuntu  | FireFox | Apache    | Ubuntu   |
| Ubuntu   | FireFox | NGINX     | CentOS   |
| Windows  | Edge    | NGINX     | CentOS   |
| MacOS    | FireFox | NGINX     | Ubuntu   |
| Windows  | FireFox | NGINX     | CentOS   |
| MacOS    | Edge    | Apache    | CentOS   |
| Lubuntu  | Chrome  | Apache    | CentOS   |
| Kubuntu  | Edge    | NGINX     | CentOS   |
| Lubuntu  | FireFox | Apache    | CentOS   |
| Xubuntu  | FireFox | NGINX     | Ubuntu   |
| Ubuntu   | Edge    | Apache    | Ubuntu   |
| Kubuntu  | Chrome  | NGINX     | Ubuntu   |
| CentOS   | FireFox | Apache    | Ubuntu   |

#### エイリアスあり

| ClientOS | Browser | WebServer | ServerOS |
| -------- | ------- | --------- | -------- |
| MacOS    | Edge    | NGINX     | Ubuntu   |
| Ubuntu   | FireFox | Apache    | CentOS   |
| Windows  | Edge    | NGINX     | CentOS   |
| CentOS   | FireFox | Apache    | Ubuntu   |
| Kubuntu  | Edge    | Apache    | Ubuntu   |
| MacOS    | Chrome  | Apache    | CentOS   |
| CentOS   | Edge    | NGINX     | CentOS   |
| Windows  | Chrome  | Apache    | Ubuntu   |
| MacOS    | FireFox | NGINX     | Ubuntu   |
| Windows  | FireFox | NGINX     | CentOS   |
| CentOS   | Chrome  | NGINX     | Ubuntu   |
| Xubuntu  | Chrome  | NGINX     | Ubuntu   |

テストケース数がエイリアスなしの時に19件、エイリアスありの時に12件で7件減らすことが出来ました！

## まとめ

いつか出くわすかもしれない膨大な組み合わせに対処できるように、PICTを学んでみました。
PICTは便利なオプションも用意されていて、とても柔軟性の高いツールとなっています。
ここでは紹介することができなかった機能もありますが、それらの機能を適切に使用することで、さらに効果的・効率的なテストケースを生成することが出来るようです。
また、PICTは組み合わせが生じる場面であれば、単体テスト、結合テスト、システムテストのいずれでも利用することができます。
参考にPICTのGithubを載せておきますので、是非お試しください！

:::note info
株式会社BTMではエンジニアの採用をしております。
ご興味がある方は是非[こちら](https://www.b-tm.co.jp/recruit/mid-career.html)をご覧ください。
:::

## 参考

[Github PICT](https://github.com/microsoft/pict)