JaSST’12 Kyushu

背景1

ソフトウェアテストシンポジウム 2012 九州• 近年、ITが社会の隅々まで浸透– システムやソフトウェアのもたらす経済的・社会的影響の増大

Javaプログラムのための単体テスト並列実行ツールの試作• ソフトウェアの重要性– 高い品質が求められる
一方で・・・

宮崎大学 工学部 情報システム工学科• 情報システムの傾向– 大規模化– 複雑化– 短納期化西川拳太，松岡慎吾，片山徹郎©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

ソフトウェアの品質確保が問題となっている©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

品質確保の手段2

単体テストはなぜ重要か？-（V字モデル）

3• ソフトウェアの品質を確保するには？

• 単体テスト– テスト工程において、最初の段階で行われるテスト

ソフトウェアの不具合を減らすこと

後工程で見つかった欠陥ほど修正コストがかかる

そのためには要求定義• テストは欠かすことの出来ない工程

システムテスト基本設計– その中でも，単体テストは特に重要手戻り発生詳細設計

結合テスト

単体テスト

実装

©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

この時点で多くの不具合（欠陥）が発見できれば，その分，後工程での手戻りを防ぐことができる©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

単体テスト

4

情報システムの傾向

5• 単体テスト• 大規模化– デバックや仕様変更の際には，全ての単体テストからテストし直すことが理想的である⇒繰り返しテストを行うことが必要とされる• 複雑化– テストの対象数が最も多く，実行や管理に手間がかかる• 短納期化 テストに多く時間を割きたい

ソフトウェアの品質を確保するためにも，テストに多くの時間を割きたい

しかし 短納期化の傾向から，テスト時間は圧縮されがち
2012/11/1©Kenta ，NISHIKAWA

2012/11/1©Kenta ，NISHIKAWA

JaSST’12 Kyushu

JaSST’12 Kyushu

目的6コーディングとテストの並列化

7• コーディング（実装）とテストの並列化を行うことで，開発工期の短縮を実現する

従来の開発（直列型）

Ｃ１

Ｔ１

並列型開発

Ｃ１-１ Ｃ１-２ Ｃ１-３

シ ステ ム テスト

要求定義

結合テ スト

基本設計

詳細設計

単体テ ストTHIS IS IT！
（これだ！）

並列実装＋単体テスト

実装

Ｔ１-１

Ｔ１-２

Ｔ１-３

短縮期間

• 目的達成のアプローチ⇒並列実行ツールの試作出来たものから随時テストを実行することで，開発工期を短縮できる©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

単体テスト並列実行ツールの特徴

8

ツール外観

9

1. 対象言語：Java

網羅した行は随時，緑色で塗り潰される

2. テスト用コードを自動で生成，実行，更新

コーディング中にバックグラウンドでテストを実行– テスト用コードは，カバレッジの取得やテストデータを入力するために必要となる– テスト対象コードの更新を検知した後，テスト用コードも自動で更新する– 更新とはテスト対象コードを上書き保存することであり，コードの中身を変更せずに上書き保存した場合も更新したとみなす
テスト対象コードを更新すると，自動でテスト用コードも更新

3. ランダムテストとカバレッジの計測– -32768～32767の範囲でランダムにテストデータを生成– テスト用コードを用いて，ステートメントカバレッジ（C0）を計測する©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

ツールの全体構成

10

テスト用コードの生成規則と生成例-（更新前）11

単体テスト並列実行ツール

正規表現を用いた解析を行う• 解析結果を用いてテスト用コードを生成

入力

テスト対象コード

テスト対象コード解析部
解析結果を用いてテスト用コードを生成（※後述）

テスト用コード

生成

テスト用コード生成部

呼び出し

実行結果

出力

停止ボタンが押されるまでランダ
ムテストを実行

テスト実行部
更新
なしCSVファイル

更新確認部
更新あり

2012/11/1

public class FizzBuzz {public static void main(String[] args) {int i;}}©Kenta ，NISHIKAWA

生成解析

テスト対象コード（更新前）

package TestPack;public class TestCode {public static void TestMain() {JTool.c0[2]=1;
int i;JTool.c0[3]=1;}}

テスト用コード

置換前

置換後

説明なし

package TestPack;

パッケージの挿入

class [クラス名]{class TestCode{

クラス名の書き換えpublic static void main()public void TestMain()main関数の書き換え

System.in.read([変数名]);

JTool.read([変数名]);

標準入力命令の書き換え[命令文];[命令文];JTool.c0[行数]=1;

カバレッジ計測文の埋め込み2012/11/1©Kenta ，NISHIKAWA

JaSST’12 Kyushu

JaSST’12 Kyushu

テスト用コードの生成規則と生成例-（更新後）12• テスト対象コードが更新されるたびに，テスト用コードを生成する
public class FizzBuzz {public static void main(String[] args) {int i;
i = readNumber();}
public static int readNumber() {byte b[] = new byte[100];try {System.in.read(b);return Integer.parseInt((new String(b)).trim());}catch (Exception e) {return 0;}}}

package TestPack;public class TestCode {public static void TestMain() {JTool.c0[2]=1;
int i;JTool.c0[3]=1;
i = readNumber();JTool.c0[4]=1;}
public static int readNumber() {JTool.c0[6]=1;
byte b[] = new byte[100]; JTool.c0[7]=1;
try {JTool.c0[8]=1;
JTool.read(b); JTool.c0[9]=1;
JTool.c0[10]=1;return Integer.parseInt((newString(b)).trim());}catch (Exception e) {JTool.c0[11]=1;
JTool.c0[12]=1;return 0;
}
}
}

生成

テスト対象コード（更新後）実行結果の出力13• テスト対象コードの更新を確認したらCSVファイルを作成– [テスト対象ファイル名]_年_月_日_時_分_秒.csv– 例）FizzBuzz_2012_11_1_15_40_23.csv• 作成されたCSVファイルにテストの実行結果を出力– テスト実行時に生成された乱数– 標準出力テスト用コード©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

適用例

14

検証内容と方法

15• 試作したツールが正しく動作することを検証するため，以下に示すJavaプログラムに適用した

FizzBuzzプログラム‒ 入力した数字が３で割り切れる場合は“ｆizz”，５で割り切れる場合は“buzz”，両者で割り切れるなら“fizzbuzz”，どれにも当てはまらない場合は数字をそのまま出力するプログラム

1 public class FizzBuzz {2public static void main(String[] args) {3int i;4
i = readNumber();
5if (i % 3 == 0 && i % 5 == 0) {6System.out.println("fizzbuzz");7} else if (i % 3 == 0) {8System.out.println("fizz");9} else if (i % 5 == 0) {10System.out.println("buzz");11} else {12System.out.println(String.valueOf (i));
13}
14}
15
public static int readNumber() {16byte b[] = new byte[100];17try {18System.in.read(b);19
return Integer.parseInt((new String(b)).trim());
20} catch (Exception e) {21
return 0;22}
23}
24 }

©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

 検証方法‒ 右図に示すプログラムを最終的に作成するプログラムとして，ツールを適用しながらコーディングを開始するテスト対象コード
public class FizzBuzz {public static void main(String[] args) {}}©Kenta ，NISHIKAWA

ファイルの更新-（２更新目）• プログラマがコーディング中に，新たにメソッドを実装し更新（上書き保存）すると，テスト用コードも自動で更新

テスト用コード
123
45

package TestPack;public class TestCode {public void TestMain() {Jtool.c0[2]= 1;}}

テスト対象コード

テスト用コード

1 public class FizzBuzz {2public static void main(String[] args) {3
int i;
4i = readNumber();5
if (i % 3 == 0 && i % 5 == 0) {6
System.out.println("fizzbuzz");7} else if (i % 3 == 0) {8System.out.println("fizz");9} else if (i % 5 == 0) {10System.out.println("buzz");11} else {12System.out.println(String.valueOf(i));
13}
14}
15
public static int readNumber() {16byte b[] = new byte[100];17try {18System.in.read(b);19
return Integer.parseInt((new String(b)).trim());
20} catch (Exception e) {21
return 0;
22}
23}
24 }

1 package TestPack;
2 public class TesaCode {3public void TestMain() {Jtool.c0[2]=1;
4int i;Jtool.c0[3]=1
5i = readNumber();Jtool.c0[4]=1
6if (i % 3 == 0 && i % 5 == 0) {Jtool.c0[5]=1;
7System.out.println("fizzbuzz");Jtool.c0[6]=1;8} else if (i % 3 == 0) {9System.out.println("fizz"); Jtool.c0[8]=1;10} else if (i % 5 == 0) {11System.out.println("buzz"); Jtool.c0[10]=1;12} else {13System.out.println(String.valueOf(i)); Jtool.c0[12]=1;
14}
15}
16
public static int readNumber() {Jtool.c0[15]=1;
17byte b[] = new byte[100]; Jtool.c0[16]=1;18
try {Jtool.c0[17]=1;
19System.in.read(b); Jtool.c0[18]=1;
20 Jtool.c0[19]=1;
return Integer.parseInt((new String(b)).trim());
21} catch (Exception e) {22 Jtool.c0[21]=1;
return 0;
23}
24}
25 }

更新

更新

2012/11/1

1 public class FizzBuzz {2public static void main(String[] args) {3int i;4i = readNumber();
5if (i % 3 == 0 && i % 5 == 0) {6System.out.println("fizzbuzz");7} else if (i % 3 == 0) {8System.out.println("fizz");9} else if (i % 5 == 0) {10System.out.println("buzz");11} else {12System.out.println(String.valueOf(i));
13}
14}
15
public static int readNumber() {16byte b[] = new byte[100];17try {18System.in.read(b);19
return Integer.parseInt((new String(b)).trim());
20} catch (Exception e) {21
return 0;
22}
23}
24 }

2012/11/1

17• クラスとメインメソッドを実装したテスト対象コードに対し，ツールがテスト用コードを自動で生成• コーディング中に，バックグラウンドでランダムテストを実行
1
2
3
4

1. テスト用コードを自動で生成，実行，更新していること
2. ステートメントカバレッジ（C0）が取得できること
3. テストの実行結果を参照できること

JaSST’12 Kyushu

ファイルの更新-（１更新目）

16

 検証内容©Kenta ，NISHIKAWA

2012/11/1©Kenta ，NISHIKAWA

JaSST’12 Kyushu

JaSST’12 Kyushu

カバレッジの取得状況と実行結果

18

検証結果

19

• 適用例から，以下の検証内容をすべて満たした
1. テスト用コードを自動で生成，実行，更新していること

入力値（ランダムに生成されたテストデータ）

2. ステートメントカバレッジ（C0）が取得できること

１ 秒間に３ ０ 回テストを実行

3. テストの実行結果を参照できること

カ バレッジと実行時間（ミリ秒）の表示

 すなわち，試作したツールが正しく動作することを確認できた
出力値©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

JaSST’12 Kyushu

考察

20©Kenta ，NISHIKAWA

2012/11/1

考察-（問題点）

21• 開発工期の短縮を目的として，単体テスト並列実行ツールを試作した• 適用例から，以下に示すいくつかの問題点を発見した
テストデータに重複が出てくる場合がある

本研究で試作したツールを使用することで，Javaプログラムを対象としたコーディングとテストの並列化を可能にするint型以外の型を引数としているメソッドに対応できないコーディングとテストを並列化することで，ソフトウェア開発における開発工期の短縮，開発量の増加，さらには品質の確保につながると考えられる©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu©Kenta ，NISHIKAWA

2012/11/1

JaSST’12 Kyushu

まとめ22

プログラムによっては，カバレッジを100%満たすまでに時間を要する可能性がある

今後の課題

23

目的

実用性の検証開発工期の短縮⁃ 具体的に，どの程度の割合で工期の短縮が実現できるのか

アプローチ

ツールの制限単体テスト並列実行ツールの試作⁃ int型で表せる数値の範囲のみをテストデータとしている⁃ 実行結果と期待値の照合ができないコーディングとテストを並列化することで・・・– テスト時間が圧縮されず，開発量の増加が見込まれる– ソフトの品質確保につながり，開発工期の短縮が期待できる
2012/11/1©Kenta ，NISHIKAWA

ブランチカバレッジ（C1）への対応⁃ C０だけではテスト強度として弱い
2012/11/1©Kenta ，NISHIKAWA