投稿理由
・ソフトウェアテスト技法練習帳でデシジョンテーブルについて勉強したので記録に残します。
内容はCodepenで動く実物と設計書(もどき)です。
対象読者
・ソフトウェアテストのデシジョンテーブルの例を確認したい方。プロダクトコードとテストコードを確認できます。
工夫したこと
・動作環境はブラウザのみする
情報共有をしやすくしたいため、プログラマ以外の端末でも動作環境を確保できるようにする。
極力docker,node.jsなどを動作環境に含めたくない。
(テストコードの動作環境はdocker有り)
・プロダクトコードは動けば良いというレベルで実装しています。そこまで力入れてません。
成果物
codepen
See the Pen software_test_2_04 by RYA234 (@rya234) on CodePen.
プロダクトコード
動作環境
名称 | version | 説明 |
---|---|---|
GoogleChrome | 131.0.6778.86 | ウェブブラウザ |
<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 |
// 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],
])('2択^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);
});
});
ドキュメント
ユースケース記述
項目名 | 説明 |
---|---|
ユースケース | 魔王を倒す |
主アクター | ユーザ |
事前条件 | なし |
主シナリオ | 1.魔王がいる部屋を探す2.魔王がいる部屋に入る3.魔王を倒す |
成功時保証 | ---- |
ビジネスルール |
ビジネスルール
項目名 | 説明 |
---|---|
ビジネスルール名 | 部屋を探し出すための条件 |
内容 | まほうのつえか賢者が必要 |
項目名 | 説明 |
---|---|
ビジネスルール名 | 部屋に入るための条件 |
内容 | くらやみのカギが必要 |
項目名 | 説明 |
---|---|
ビジネスルール名 | 魔王を倒す条件 |
内容 | ひかりの剣が必要 |
画面項目
項目名 | 表示名 | I/O | プロパティ(物理名) | 種類 | 備考 |
---|---|---|---|---|---|
タイトル | 魔王との戦い | O | title | ラベル | _ |
仲間:賢者 | -- | I | sage | チェックボックス | _ |
持物:まほうのつえ | -- | I | staff | チェックボックス | _ |
持物:くらやみのかぎ | -- | I | key | チェックボックス | _ |
持物:ひかりの剣 | -- | I | sword | チェックボックス | _ |
実行 | 倒せるか判定 | I | run | ボタン | clickイベント有り |
結果 | 結果:XXX | O | result | ラベル | clickイベント実行後に値が変化する |
イベント処理
ボタン onClickイベント
入力項目に対して、入力規則を満たしているか確認する。
頻繁に使うので、クライアントで実行
ライフライン名 | 分類 | 説明 |
---|---|---|
input | HTML | id=sage,staff,key,swordに該当 |
button | HTML | id=runが該当 |
message | HTML | id= resultに相当 |
event | JS | Clickイベントハンドラー |
singleItemCheck | JS | ビジネスルール「部屋を探し出すための条件」「部屋に入るための条件」「魔王を倒す条件」 |
ノートに書いた下書き
参考
github 差分
「はじめての設計をやり抜くための本 第2版」 p95 ユースケース分析
qiitaにCodepenを埋め込む
「ソフトウェアテスト技法練習帳 ~知識を経験に変える40問」