Java はじめて26 〜JUnitでのテスト駆動型開発3: クラスの実装〜

イントロダクション

JUnitを使用したテスト駆動開発について記載しています。
前回は、どのようにテストケースを実装したら良いか?とか実装する手法について記載しました。

<JUnitの起動設定1>

<同様に2>

Junitのサンプルコード

JUnitでのテストを行うために必要なことは

  1. junit.jarを設定
  2. テストメソッドに「\@Test」をつける

より簡単にテストを行いたければ、「/@Before」などのアノテーションを使う。

public class TestSample {
    /** テスト対象クラス */
    private Sample target;
    @Before
    public void initTest() {
        // テストの実行準備の処理
        target = new Sample();
    }
    @Test
    public void test001() {
        assertEquals("a", "a"); // 二つの引数が等しいことを確認できる。
    }
}

クラスの実装

今回は、JUnitでのテストケースから、テストをオールグリーンに出来る様に実体クラスを作成します。
つまり、JUnitでテストケースを要件を満たす様に作成し、テスト実行後に緑色の表示がされる様にKozaManagerのメソッドを作成します。これは、銀行のATMを簡易的にしたコンソールアプリを作成するための実装でもあります。
ちなみに、今回の実装する時の要件は以下の様になっています。

  1. ファイルを操作するためのオブジェクトを作成する
  2. ファイルにデータをCSV形式で書き出す。
  3. ファイルが存在するのであれば、それを読み込みデータを保持する

クラスを仕分けしてからの実装を行うので、どの様に考えれば良いか?の指針になれば良いと思います。

<クラスの仕分けの例>

  • File操作担当のクラスを作成する(仮にFileUtilクラスとする)
  • KozaManagerからFile操作をするときはこのクラスを呼ぶようにする

<KozaMangerでの実装例>

public class KozaManger {
    ...
    public boolean isFile() {
        return FileUtil.isFile("reources/koza.csv");
    }
    ...
}

<テストケース(メソッド)の例>

@Test
public void testIsFile() {
    // 存在しないファイルを指定したときはFALSEを返す
    boolean isFalse = FileUtil.isFile("resources/koza.xyz");
    assertFalse(isFalse);
    // 存在するファイルを指定したときはTRUEを返す
    boolean isTrue = FileUtil.isFile("resources/koza.csv");
    assertTrue(isTrue);
}

<FileUtilでの実装例>※テストしていません。。。
※JavaDocを参照:File#isFile()

public static boolean isFile(String path) {
    File file = new File(path);
    return file.isFile(path);
}

<ファイル入出力のテスト>

今までの概要

前回作成したのは、上の要件のうちの1(コンストラクタで実装)だけです、これはテストを実行する準備段階でもあるので、テストケースとしては「インスタンスがtargetに設定されていること」を確認するテストケースを作成しました。

public class KozaManager {
    /** ファイルへの書き出しクラス */
    private BufferedWriter write;
    /** ファイルの読み込みクラス */
    private BufferedReader read;
    /** コンストラクタ */
    public KozaManager() {
        // 操作するファイルを指定する
        File file = new File("resources/koza.csv");
        try {
            write = new BufferedWriter(new FileWriter(file));
            if (file.exists()) {
                read = new BufferedReader(new FileReader(file));
            }
        } catch (IOException ie) {
            ie.printStackTrace();
            System.out.println("ファイルオープンに失敗しました。" + ie.getMessage());
            System.exit(-1);
        }
    }
    /** デストラクタ */
    @Override
    protected void finalize() throws Throwable {
        write = null;
        read = null;
        }
    /**
    * データクラスを受け取り、CSVファイルを出力する(書き出しを行う)
    * @param data コーダー銀行のユーザー情報
    */
    public void dataOutput(Data data) {
    // スタブの状態(空実装)
    }
}

コンストラクタと、デストラクタを実装しています。
コンストラクタは、ファイル操作に必要なクラスのインスタンスを作成します。
デストラクタは作成したインスタンスを解放(Nullをセット)します。※メモリの開放をすることでリソースの節約になります。

作成したデストラクタは明示的に呼び出しましょうつまり使い終わったら下のように「finalize()」を呼び出しましょう。
ガベージコレクションに任せると、いつ呼び出されるかわかりません。。。

KozaManager kozaManager = new KozaManager();
// 何かしらの処理 ...

// メモリの開放 finalize()を明示的に呼び出す
kozaManager.finalize();

現状のテストコード

package jp.zenryoku.apps.atm.manage;
import static org.junit.Assert.assertNotNull;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import jp.zenryoku.apps.atm.data.Data;
/**
* @author takunoji
*
* 2019/09/25
*/
public class KozaManagerTest {
    /** テスト対象クラス */
    private KozaManager target;
    /**
    *  テストの初期化
    *  各テスト実行前に起動する
    */
    @Before
    public void init() {
        target = new KozaManager();
    }

    /**
     * テスト終了時にメモリの開放処理を行う
     */
     @After
     public void finish() {
        // デストラクタを明示的に呼び出す。
        target.finalize();
     }
    /**
    * コンストラクタが起動したかどうかを確認する
    * テストケース
    */
    @Test
    public void testIsFile() {
        assertNotNull(target);
    }
    /**
    * ファイルにデータを出力し保存するテストケースです。
    */
    public void testFileCeate() {
    }
}

テストケース作成

今回の目玉になります、現状はから実装になっている「testFileCreate()」の実装を行いますが、これはテスト対象クラス(本来作成するクラス)がどう動けば良いか?を考えて作成する必要があります。

どう動けば良いか?

口座情報管理(KozaManager)クラスで入力されたデータをファイルに出力する必要があるので単純に「データを受けて、それをCSVに変換してファイル出力する」処理を行うのがこのメソッドの処理になります。
まとめると以下の様になります。

  1. 入力としてDataクラス(口座情報クラス)を受ける
  2. 出力として、CSVファイルを出力する

ここで、KozaManagerクラスの他に「Dataクラス」が必要であることがわかります。これは前回作成しております
そして、CSVファイルを出力するのに、ヘッダー部分のテンプレート(CSVファイルのヘッダは固定値です)を出力する必要がありますので、これをKozaManagerに追加します。
現状では、以下の様なコードになります。

/**
* 出力するCSVのヘッダー部分を作成する。
* @return CSVヘッダーの文字列(カンマ区切り)
*/
private String createCSVHeader() {
    return "名前, パスワード";
}
/**
* データクラスを受け取り、CSVファイルを出力する(書き出しを行う)
* @param data コーダー銀行のユーザー情報
*/
public void dataOutput(Data data) throws IOException {
    StringBuilder build = new StringBuilder();
    build.append(this.createCSVHeader());
    build.append(data.getName() + ",");
    build.append(data.getPassword());
}

しかし、ここで注意したいのがCSVデータは大雑把に以下の様な形式になります。そして、サンプルデータを記載しておきます。
<形式>
1行目: ヘッダー
2行目以降: データ

名前, パスワード
テスト太郎, 1234
テスト花子, 2345
テストたくのじ, 3456

頭をひねる

ここで、元のクラスに色々と修正を加える必要が出てきました。追加する修正は以下のものです。

  1. ファイル出力する時のパス指定をハードコーディング(File file = new File("resources/koza.csv");)しているのを定数としてクラスに保持したい
  2. ファイルが出力できたか?のファイル存在チェックメソッドが欲しい

これらの修正を加えるのに、テストケースで「ファイルにデータをCSV形式で書き出す。」という処理は最後になります。
上の処理を確認するのにファイルの存在チェックなどが必要なので先にそちらの処理を作成する必要があるからです。

先にファイル存在チェック処理を作る

これをやる必要が出てきました。
これは次回やろうと思います。

Java はじめて27 〜JUnitでのテスト駆動型開発4: 追加修正と実装〜

でわでわ。。。

<<< 前回 次回 >>>

<Java関連の動画リスト>

<JUnit関連の動画リスト>



投稿者:

takunoji

音響、イベント会場設営業界からIT業界へ転身。現在はJava屋としてサラリーマンをやっている。自称ガテン系プログラマー(笑) Javaプログラミングを布教したい、ラスパイとJavaの相性が良いことに気が付く。 Spring framework, Struts, Seaser, Hibernate, Playframework, JavaEE6, JavaEE7などの現場経験あり。 SQL, VBA, PL/SQL, コマンドプロント, Shellなどもやります。

コメントを残す