ソフトウェアテスト技法練習帳　デシジョンテーブル_2_04

## 投稿理由
・ソフトウェアテスト技法練習帳でデシジョンテーブルについて勉強したので記録に残します。
  内容はCodepenで動く実物と設計書（もどき）です。

## 対象読者
・ソフトウェアテストのデシジョンテーブルの例を確認したい方。プロダクトコードとテストコードを確認できます。

## 工夫したこと
・動作環境はブラウザのみする
　情報共有をしやすくしたいため、プログラマ以外の端末でも動作環境を確保できるようにする。
　極力docker,node.jsなどを動作環境に含めたくない。
 　（テストコードの動作環境はdocker有り）
 
・プロダクトコードは動けば良いというレベルで実装しています。そこまで力入れてません。



# 成果物
## codepen


<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="WbejYYO" data-pen-title="software_test_2_04" data-user="rya234" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/rya234/pen/WbejYYO">
  software_test_2_04</a> by RYA234 (<a href="https://codepen.io/rya234">@rya234</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>



## プロダクトコード

動作環境

名称|version|説明
---|--------|---
GoogleChrome|131.0.6778.86|ウェブブラウザ


```html
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>2_04 魔王との戦い</title>
</head>
<body>
    <h1>2_04 魔王との戦い</h1>
    <div>
        <h2>仲間</h2>
        <div>
            <ul>
                <li>
                賢者
                <input type="checkbox" id="sage" name="sage" />
                <label for="sage">有</label>
                </li>
            </ul>
        </div>
        <h2>持ち物</h2>
        <div>
            <ul>
                <li>
                    まほうのつえ
                    <input type="checkbox" id="staff" name="staff" />
                    <label for="staff">有</label>
                </li>
                <li>
                    くらやみのかぎ
                    <input type="checkbox" id="key" name="key" />
                    <label for="key">有</label>
                </li>
                <li>
                    ひかりのかぎ
                    <input type="checkbox" id="sword" name="sword" />
                    <label for="sword">有</label>
                </li>
            </ul>

        </div>
    </div>
    <button id="run">魔王を倒せるか判定</button>
    <div id="result" style="color:red;"> </div>
<script>
    let currentEnchant = [0,0,0,0];
    const maxEnchant = [0,0,0,1];
    const  weapon_id =["hinoki","ninjin","kikori","kusanagi"];

    // event 系
window.onload = (event) => {

    const sageCheckBox = document.getElementById('sage');
    const staffCheckBox = document.getElementById('staff');
    const keyCheckBox = document.getElementById('key');
    const swordCheckBox = document.getElementById('sword');
    const button = document.getElementById('run');
    const result = document.getElementById('result');
    
    const normalPrice = 490;
    const couponPrice = 100;
    const happyHourPrice = 290;

    // ボタンクリック時の処理
    button.addEventListener('click', event => {
        if(!(sageCheckBox.checked || staffCheckBox.checked) ){
            result.innerHTML = "結果:部屋を探し出せませんでした。";
            return
        }

        if(!keyCheckBox.checked){
            result.innerHTML = "結果: 部屋を探しだしました。しかし、鍵がないので部屋に入れません。";
            return
        }
        if(!swordCheckBox.checked){
            result.innerHTML = "結果: 部屋を探しだしました。そして、部屋に入れました。しかし、魔王を倒すには剣が必要です。";
            return
        }
        result.innerHTML = "結果: 部屋を探しだしました。そして、部屋に入れました。魔王を倒しました。";
    });
}
</script>
</body>
</html>

```


## テストコード

開発環境
名称|version|説明
---|--------|---
Javascript|-|プログラミング言語
HTML|HTML Living Standard|GUI
docker|27.0.3-1|コンテナ型仮想環境
Nodejs|22.9.0|単体テスト実行で使う
Jest|29.70|テストフレームワーク
jsdom|25.01|DOM操作のライブラリ　テストで使う
Github Codespaces|-|クラウドIDE


```js
// import {fromFile} from '@testing-library/jsdom';
import { test } from '@jest/globals';
import fs from "fs/promises";
import { JSDOM } from "jsdom";
// 実行コマンド
// docker-compose exec -it webserver bash -c  "npm test 2_04.test.js"
// 参考にしたやつ
// https://symfoware.blog.fc2.com/blog-entry-2685.html

;
describe('2_04 魔王との戦い', () => {

  let html="";
  let dom = ""
  beforeEach(async() => {
    html = await fs.readFile("software_test/02Decision_Table/2_04/2_04.html")
    dom =  new JSDOM(html,{runScripts: "dangerously"});
    dom.window.onload();
  })


  const badResult1= "部屋を探し出せませんでした。";
  const badResult2= "部屋を探しだしました。しかし、鍵がないので部屋に入れません。";
  const badResult3= "部屋を探しだしました。そして、部屋に入れました。しかし、魔王を倒すには剣が必要です。";
  const bestResult= "部屋を探しだしました。そして、部屋に入れました。魔王を倒しました。";
  

  test.each([
    [false,false,false,false,badResult1],
    [false,false,true,false,badResult1],
    [false,false,false,true,badResult1],
    [false,false,true,true,badResult1],
    [true,false,false,true,badResult2],
    [true,false,false,false,badResult2],
    [false,true,false,false,badResult2],
    [false,true,false,true,badResult2],
    [true,true,false,true,badResult2],
    [true,true,false,false,badResult2],
    [true,true,true,false,badResult3],
    [false,true,true,false,badResult3],
    [true,false,true,false,badResult3],
    [true,true,true,true,bestResult],
    [true,false,true,true,bestResult],
    [false,true,true,true,bestResult],
  ])('２択^4（=16）のデシジョンテスト', async(isSage,isStaff,isKey,isSword,expectedResult) => {
        
       // テキスト入力欄を取得し値を設定
        const button = dom.window.document.getElementById('run');
        const sageCheckBox = dom.window.document.getElementById("sage");
        const staffCheckBox = dom.window.document.getElementById("staff");
        const keyCheckBox = dom.window.document.getElementById("key");
        const swordCheckBox = dom.window.document.getElementById("sword");
        const result = dom.window.document.getElementById('result');
        
        sageCheckBox.checked = isSage;
        staffCheckBox.checked = isStaff;
        keyCheckBox.checked = isKey;
        swordCheckBox.checked = isSword;

        // クリック
        button.click();

        // 結果の取得
        expect(result.innerHTML).toContain(expectedResult);
  });

});
```



# ドキュメント

## ユースケース記述
項目名|説明
--|---
ユースケース|魔王を倒す
主アクター|ユーザ
事前条件|なし
主シナリオ|１．魔王がいる部屋を探す</br>２．魔王がいる部屋に入る</br>３．魔王を倒す
成功時保証|  ----
ビジネスルール| 



## ビジネスルール
項目名|説明
--|---
ビジネスルール名|部屋を探し出すための条件
内容|まほうのつえか賢者が必要

項目名|説明
--|---
ビジネスルール名|部屋に入るための条件
内容|くらやみのカギが必要


項目名|説明
--|---
ビジネスルール名|魔王を倒す条件
内容|ひかりの剣が必要


## 画面項目

項目名|表示名|I/O|プロパティ(物理名)|種類|備考
-----|-----|---|--------|---|---
タイトル|魔王との戦い|O|title|ラベル| _|
仲間：賢者|--|I|sage|チェックボックス| _|有
持物：まほうのつえ|--|I|staff|チェックボックス| _|有
持物：くらやみのかぎ|--|I|key|チェックボックス| _|有
持物：ひかりの剣|--|I|sword|チェックボックス| _|有
実行|倒せるか判定|I|run|ボタン| clickイベント有り|
結果|結果：XXX|O|result|ラベル|clickイベント実行後に値が変化する|


## イベント処理

### ボタン　onClickイベント
　入力項目に対して、入力規則を満たしているか確認する。
　頻繁に使うので、クライアントで実行

```plantuml
@startuml
title button click event
autonumber
actor user

box HTML
participant text as "input"
participant Button as "button"
participant output as "result"

endBOX
box javascript
 participant event
 participant logic

 
 user --> text:input checkboxs
 user --> Button:pressButton
 activate event
 Button --> event:call event handler
    event -> logic :  set input
    logic -> event : return result
    event --> output :  display result

 deactivate event
endbox
@enduml
```




ライフライン名|分類|説明
------------|----|---
input|HTML|id=sage,staff,key,swordに該当
button|HTML|id=runが該当
message|HTML|id= resultに相当
event|JS| Clickイベントハンドラー
singleItemCheck|JS| ビジネスルール「部屋を探し出すための条件」「部屋に入るための条件」「魔王を倒す条件」

# ノートに書いた下書き

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/213b6a6c-dbf4-49cc-0fe3-091942574b3c.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/d0bdfb66-4c2a-9b5d-3cd4-87c59973b6f4.png)









# 参考

github 差分

https://github.com/RYA234/routine_tool/commit/5c148cb0413a8b9f360ea031af3b7ceddb620703


「はじめての設計をやり抜くための本　第２版」　p95 ユースケース分析

qiitaにCodepenを埋め込む

https://qiita.com/Qiita/items/edae7417214c8e957f54

「ソフトウェアテスト技法練習帳 ~知識を経験に変える40問」