【Java】作成したCSVファイルと期待値が一致するかチェックする

■概要

作成する処理の概要は以下の通り。

  • 作成したCSVファイル(以降、実測値とする)を読み込む
  • データ項目が期待値通りか確認する
  • 1レコードずつ取得し、1カラムずつ一致している確認する
  • CSVファイル内のデータについて、日付は対象外

なお、実測値および期待値については、それぞれMap(HashMap)に値を格納し、比較するものとする。

・ファイル読み込み
・比較
・ファイル読み込み ・比較
実測値
(CSVファイル)
実測値 (CSVファイル)
期待値
(CSVファイル)
期待値 (CSVファイル)
差分結果出力
差分結果出力
Text is not SVG – cannot display

■CSVファイルのデータ項目

実測値および期待値のデータ項目は以下に示す。

なお、実測値および期待値は2種類用意する。

▼Case1:実測値に余剰なデータあり

・実測値

idvalue1value2value3date
(YYYYMMDD)
001hoge1huga1hgehuga120241102
002hoge9huga2hgehuga220241103
003hoge3huga9hgehuga320241104
004hoge4huga4hgehuga920241105
005hogehugahgehuga20241106
009hoge9huga9hgehuga920241110
※1 余剰分は赤字、不一致は緑字で示す
※2 日付は比較対象外

・期待値

idvalue1value2value3date
(YYYYMMDD)
001hoge1huga1hgehuga120241002
002hoge2huga2hgehuga220241003
003hoge3huga3hgehuga320241004
004hoge4huga4hgehuga420241005
005hoge5huga5hgehuga520241006
※1 不一致は緑字で示す
※2 日付は比較対象外

▼Case2:実測値に必要なデータなし(期待値に余剰データあり)

・実測値

idvalue1value2value3date
(YYYYMMDD)
001hoge1huga1hgehuga120241102
002hoge9huga2hgehuga220241103
003hoge3huga9hgehuga320241104
004hoge4huga4hgehuga920241105
005hogehugahgehuga20241106
※1 不一致は緑字で示す
※2 日付は比較対象外

・期待値

idvalue1value2value3date
(YYYYMMDD)
001hoge1huga1hgehuga120241002
002hoge2huga2hgehuga220241003
003hoge3huga3hgehuga320241004
004hoge4huga4hgehuga420241005
005hoge5huga5hgehuga520241006
009hoge9huga9hogehuga920241010
※1 余剰分は赤字、不一致は緑字で示す
※2 日付は比較対象外

■クラス図

実装するモジュールのクラス図を以下に示す。

■モジュールのディレクトリ階層

実装するモジュールのディレクトリ階層を以下に示す。

expectedvaluecheck
├── expected
│   └── expected.csv
├── input
│   └── case.csv
└── src
    ├── checker
    │   └── InputExpectedChecker.java
    ├── constant
    │   ├── CsvHeaderConstant.java
    │   └── FilePathConstant.java
    ├── converter
    │   └── CsvToHashMapConverter.java
    ├── main
    │   └── ExpectedValueCheckMain.java
    └── reader
        └── CsvReader.java

■フローチャート

実装するモジュールのフローチャートを以下に示す。

▼メイン処理

ExpectedValueCheckMain.java

開始
開始
インプットファイル読み込み
インプットファイル読み込み
HashMap形式でインプット格納
HashMap形式でインプット格納
HashMap形式で期待値格納
HashMap形式で期待値格納
期待値ファイル読み込み
期待値ファイル読み込み
相互比較(期待値->実測値)
相互比較(期待値->実測値)
相互比較(実測値->期待値)
相互比較(実測値->期待値)
終了
終了
Text is not SVG – cannot display

▼CSVファイル読み込み

CsvReader.java

開始
開始
try
try
Fileオブジェクト生成
Fileオブジェクト生成
FileReaderオブジェクト生成
FileReaderオブジェクト生成
BufferedReaderオブジェクト返却
BufferedReaderオブジェクト返却
catch
catch
例外エラー出力
例外エラー出力
null返却
null返却
終了
終了
CSVファイル
CSVファイル
コンソール
コンソール
Text is not SVG – cannot display

▼CSVからHashMapへ変換

CsvToHashMapConverter.java

開始
開始
返却用HashMap作成
返却用HashMap作成
データ件数カウンタセット
データ件数カウンタセット
csvファイルの1行初期化
csvファイルの1行初期化
csvヘッダ部要素配列セット
csvヘッダ部要素配列セット
csvファイル
csvファイル
try
try
csvファイルの中身を1行ずつ繰り返し
csvファイルの中身を1行ずつ繰り返し
csvのデータ
csvのデータ
データ部
データ部
ヘッダ部
ヘッダ部
csvのデータを配列に格納
csvのデータを配列に格納
データ部格納用HashMap作成
データ部格納用HashMap作成
csvヘッダ部要素数分繰り返し
csvヘッダ部要素数分繰り返し
 {ヘッダ部要素名:csvのデータ}
形式でデータを格納
{ヘッダ部要素名:csvのデータ}…
返却用HashMap
{データカウンタ:{ヘッダ部要素名:csvのデータ}}
の形式で格納
返却用HashMap…
カウンタインクリメント
カウンタインクリメント
あり
あり
なし
なし
catch
catch
例外エラー出力
例外エラー出力
コンソール
コンソール
HashMap返却
HashMap返却
終了
終了
Text is not SVG – cannot display

▼差分比較

InputExpectedChecker.java

・期待値 -> 実測値比較(expectedInputChecker)

開始
開始
チェックフラグセット
チェックフラグセット
csvヘッダ部要素配列セット
csvヘッダ部要素配列セット
開始通知出力
開始通知出力
コンソール
コンソール
期待値のキー項目分繰り返し
期待値のキー項目分繰り返し
チェックフラグ:True
チェックフラグ:True
データケース出力
データケース出力
コンソール
コンソール
csvヘッダ部要素分繰り返し
csvヘッダ部要素分繰り返し
ヘッダ部
ヘッダ部
日付
日付
日付以外
日付以外
continue
continue
実測値
実測値
データあり
データあり
データなし
データなし
結果出力
結果出力
コンソール
コンソール
チェックフラグ:False
チェックフラグ:False
期待値と実測値
期待値と実測値
一致
一致
不一致
不一致
結果出力
結果出力
コンソール
コンソール
チェックフラグ:False
チェックフラグ:False
チェックフラグ
チェックフラグ
true
true
false
false
結果出力
結果出力
コンソール
コンソール
終了
終了
Text is not SVG – cannot display

・実測値 -> 期待値比較(inputExpectedChecker)

開始
開始
チェックフラグセット
チェックフラグセット
csvヘッダ部要素配列セット
csvヘッダ部要素配列セット
開始通知出力
開始通知出力
コンソール
コンソール
期待値のキー項目分繰り返し
期待値のキー項目分繰り返し
チェックフラグ:True
チェックフラグ:True
データケース出力
データケース出力
コンソール
コンソール
csvヘッダ部要素分繰り返し
csvヘッダ部要素分繰り返し
ヘッダ部
ヘッダ部
日付
日付
日付以外
日付以外
continue
continue
結果出力
結果出力
コンソール
コンソール
チェックフラグ:False
チェックフラグ:False
チェックフラグ
チェックフラグ
true
true
false
false
結果出力
結果出力
コンソール
コンソール
終了
終了
期待値
期待値
データあり
データあり
データなし
データなし
Text is not SVG – cannot display

■サンプルコード

実装するモジュールのコードを以下に示す。

▼メイン処理

ExpectedValueCheckMain.java

package main;

import java.io.BufferedReader;
import java.util.HashMap;

import checker.InputExpectedChecker;
import constant.FilePathConstant;
import converter.CsvToHashMapConverter;
import reader.CsvReader;

public class ExpectedValueCheckMain {

	public static void main(String[] args) {

		// インプットファイル読み込み
		BufferedReader inputFile = CsvReader.csvFileReader(FilePathConstant.INPUT_FILEPATH);

		// HashMap形式でデータを格納
		HashMap<Integer, HashMap<String, String>> inputDatas = CsvToHashMapConverter.resultHashMap(inputFile);

		// 期待値ファイル読み込み
		BufferedReader expectedFile = CsvReader.csvFileReader(FilePathConstant.EXPECTED_FILEPATH);

		// HashMap形式でデータを格納
		HashMap<Integer, HashMap<String, String>> expectedDatas = CsvToHashMapConverter.resultHashMap(expectedFile);

		// 相互比較(期待値 -> 実測値)
		InputExpectedChecker.expectedInputChecker(expectedDatas, inputDatas);

		// 相互比較(実測値 -> 期待値)
		InputExpectedChecker.inputExpectedChecker(expectedDatas, inputDatas);
	}
}

▼CSVファイル読み込み

CsvReader.java

package reader;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import constant.FilePathConstant;

// CSVファイル読み込みクラス
public class CsvReader {

  /*
   * CSVファイル読み込み処理
   * 
   * @input ファイルパス
   * 
   * @return BufferedReader
   */
  public static BufferedReader csvFileReader(final FilePathConstant path) {

    try {
      // ファイルオブジェクト生成
      final File csvFile = new File(path.getFilePathConstant());

      // FileReaderオブジェクト生成
      final FileReader fReader = new FileReader(csvFile);

      // BufferedReaderオブジェクトを返却
      return new BufferedReader(fReader);

    } catch (Exception e) {
      System.out.println("csvFileReader例外エラー:" + e);

      return null;
    }
  }
}

▼CSVからHashMapへ変換

CsvToHashMapConverter.java

package converter;

import java.io.BufferedReader;
import java.util.HashMap;
import constant.CsvHeaderConstant;

public class CsvToHashMapConverter {

  /*
   * csv -> HashMap変換処理
   * 
   * @param csvFile csvファイル情報
   */
  public static HashMap<Integer, HashMap<String, String>> resultHashMap(
      final BufferedReader csvFile) {
    // 返却用HashMap
    final HashMap<Integer, HashMap<String, String>> result = new HashMap<>();

    // データ件数カウンタ
    int dataCount = 1;

    // csvファイルの1行
    String readLine = "";

    // csvヘッダ部要素配列
    final CsvHeaderConstant[] keys = CsvHeaderConstant.values();

    // csvファイルが存在する場合
    if (csvFile != null) {
      try {
        // csvファイルの中身を1行ずつ繰り返し
        while ((readLine = csvFile.readLine()) != null) {

          // ヘッダー部以外の場合
          if (!readLine.contains(CsvHeaderConstant.ID.getCsvHeaderConstant())) {

            // csvのデータを配列に格納
            String[] items = readLine.split(",");

            // データ部格納用HashMap
            HashMap<String, String> data = new HashMap<>();

            // csvヘッダ部配列要素分繰り返し
            for (int i = 0; i < keys.length; i++) {
              // {ヘッダ部要素名:csvのデータ}形式でデータを格納=データ部
              data.put(keys[i].getCsvHeaderConstant(), items[i]);
            }
            // 返却用HashMap{データカウンタ:データ部}の形式で格納
            result.put(dataCount, data);

            // カウンタインクリメント
            dataCount++;
          }
        }
      } catch (Exception e) {
        System.out.println("resultHashMap処理例外エラー:" + e);
      }
    }
    return result;
  }
}

▼差分比較

InputExpectedChecker.java

package checker;

import java.util.HashMap;
import constant.CsvHeaderConstant;

// 相互比較クラス
public class InputExpectedChecker {

  /*
   * 期待値 -> 実測値 比較処理
   * 
   * @param expectedDatas 期待値HashMap
   * 
   * @param inputDatas 実測値HashMap
   */
  public static void expectedInputChecker(HashMap<Integer, HashMap<String, String>> expectedDatas,
      HashMap<Integer, HashMap<String, String>> inputDatas) {
    // チェックフラグ(true:比較OK、false:比較NG)
    boolean isData = true;

    // csvヘッダ部要素配列
    final CsvHeaderConstant[] keyHeaders = CsvHeaderConstant.values();

    System.out.println("##### 相互参照:期待値->実測値 #####");

    // 期待値のキー項目分繰り返し
    for (Integer keyCount : expectedDatas.keySet()) {

      // チェックフラグ初期化
      isData = true;

      System.out.println("===== データ:" + keyCount + " =====");

      // csvヘッダ部配列要素分繰り返し
      for (CsvHeaderConstant keyHeader : keyHeaders) {

        // ヘッダ部が日付の項目はチェック対象外
        if (CsvHeaderConstant.TARGET_DATE.equals(keyHeader)) {
          continue;
        }

        // 実測値にデータが存在しない場合
        if (inputDatas.get(keyCount) == null) {

          // 結果出力
          System.out.println("*** " + keyHeader.getCsvHeaderConstant() + " ***");
          System.out
              .println("期待値:" + expectedDatas.get(keyCount).get(keyHeader.getCsvHeaderConstant()));
          System.out.println("実測値:データなし");

          // チェックフラグNG
          isData = false;

          // 期待値と実測値が異なる場合
        } else if (!expectedDatas.get(keyCount).get(keyHeader.getCsvHeaderConstant())
            .equals(inputDatas.get(keyCount).get(keyHeader.getCsvHeaderConstant()))) {

          // 結果出力
          System.out.println("*** " + keyHeader.getCsvHeaderConstant() + " ***");
          System.out
              .println("期待値:" + expectedDatas.get(keyCount).get(keyHeader.getCsvHeaderConstant()));
          System.out
              .println("実測値:" + inputDatas.get(keyCount).get(keyHeader.getCsvHeaderConstant()));

          // チェックフラグNG
          isData = false;

        }
      }
      // チェックフラグOKの場合
      if (isData) {
        // 結果出力
        System.out.println("OK");
      }
    }
  }

  /*
   * 実測値 -> 期待値 比較処理
   * 
   * @param expectedDatas 期待値HashMap
   * 
   * @param inputDatas 実測値HashMap
   */
  public static void inputExpectedChecker(HashMap<Integer, HashMap<String, String>> expectedDatas,
      HashMap<Integer, HashMap<String, String>> inputDatas) {

    // チェックフラグ(true:比較OK、false:比較NG)
    boolean isData = true;

    // csvヘッダ部要素配列
    final CsvHeaderConstant[] keyHeaders = CsvHeaderConstant.values();

    System.out.println("##### 相互参照:実測値->期待値 #####");

    // 期待値のキー項目分繰り返し
    for (Integer keyCount : inputDatas.keySet()) {

      // チェックフラグセット
      isData = true;

      // 期待値が存在しない
      if (expectedDatas.get(keyCount) == null) {

        System.out.println("===== データ:" + keyCount + " =====");

        // csvヘッダ部配列要素分繰り返し
        for (CsvHeaderConstant keyHeader : keyHeaders) {

          // 日付はスキップ
          if (CsvHeaderConstant.TARGET_DATE.equals(keyHeader)) {
            continue;
          }

          System.out.println("*** " + keyHeader.getCsvHeaderConstant() + " ***");
          System.out.println("期待値:データなし");
          System.out
              .println("実測値:" + inputDatas.get(keyCount).get(keyHeader.getCsvHeaderConstant()));

          // チェックフラグNG
          isData = false;
        }
      }
    }
    // チェックフラグOKの場合
    if (isData) {
      // 結果出力
      System.out.println("OK");
    }
  }
}

▼定数

CsvHeaderConstant.java

package constant;

public enum CsvHeaderConstant {

  // ID
  ID("id"),

  // value1
  VALUE1("value1"),

  // value2
  VALUE2("value2"),

  // value3
  VALUE3("value3"),

  // 日付
  TARGET_DATE("date(YYYYMMDD)");

  // フィールド変数
  private final String header;

  // コンストラクタ
  private CsvHeaderConstant(String header) {
    this.header = header;
  }

  // ゲッター
  public String getCsvHeaderConstant() {
    return header;
  }
}

FilePathConstant.java

package constant;

public enum FilePathConstant {

  // インプットファイルパス
  INPUT_FILEPATH("input/case.csv"),

  // 期待値ファイルパス
  EXPECTED_FILEPATH("expected/expected.csv");

  // フィールド変数
  private final String filePath;

  // コンストラクタ
  private FilePathConstant(String filePath) {
    this.filePath = filePath;
  }

  // ゲッター
  public String getFilePathConstant() {
    return filePath;
  }
}

■実行結果

▼Case1:実測値に余剰なデータあり

・実測値

id,value1,value2,value3,date(YYYYMMDD)
001,hoge1,huga1,hogehuga1,20241102
002,hoge9,huga2,hogehuga2,20241103
003,hoge3,huga9,hogehuga3,20241104
004,hoge4,huga4,hogehuga9,20241105
005,hoge,huga,hogehuga,20241106
009,hoge9,huga9,hogehuga9,20241110

・期待値

id,value1,value2,value3,date(YYYYMMDD)
001,hoge1,huga1,hogehuga1,20241002
002,hoge2,huga2,hogehuga2,20241003
003,hoge3,huga3,hogehuga3,20241004
004,hoge4,huga4,hogehuga4,20241005
005,hoge5,huga5,hogehuga5,20241006

・結果

##### 相互参照:期待値->実測値 #####
===== データ:1 =====
OK
===== データ:2 =====
*** value1 ***
期待値:hoge2
実測値:hoge9
===== データ:3 =====
*** value2 ***
期待値:huga3
実測値:huga9
===== データ:4 =====
*** value3 ***
期待値:hogehuga4
実測値:hogehuga9
===== データ:5 =====
*** value1 ***
期待値:hoge5
実測値:hoge
*** value2 ***
期待値:huga5
実測値:huga
*** value3 ***
期待値:hogehuga5
実測値:hogehuga
##### 相互参照:実測値->期待値 #####
===== データ:6 =====
*** id ***
期待値:データなし
実測値:009
*** value1 ***
期待値:データなし
実測値:hoge9
*** value2 ***
期待値:データなし
実測値:huga9
*** value3 ***
期待値:データなし
実測値:hogehuga9

▼Case2:実測値に必要なデータなし(期待値に余剰データあり)

・実測値

id,value1,value2,value3,date(YYYYMMDD)
001,hoge1,huga1,hogehuga1,20241102
002,hoge9,huga2,hogehuga2,20241103
003,hoge3,huga9,hogehuga3,20241104
004,hoge4,huga4,hogehuga9,20241105
005,hoge,huga,hogehuga,20241106

・期待値

id,value1,value2,value3,date(YYYYMMDD)
001,hoge1,huga1,hogehuga1,20241002
002,hoge2,huga2,hogehuga2,20241003
003,hoge3,huga3,hogehuga3,20241004
004,hoge4,huga4,hogehuga4,20241005
005,hoge5,huga5,hogehuga5,20241006
009,hoge9,huga9,hogehuga9,20241010

・結果

##### 相互参照:期待値->実測値 #####
===== データ:1 =====
OK
===== データ:2 =====
*** value1 ***
期待値:hoge2
実測値:hoge9
===== データ:3 =====
*** value2 ***
期待値:huga3
実測値:huga9
===== データ:4 =====
*** value3 ***
期待値:hogehuga4
実測値:hogehuga9
===== データ:5 =====
*** value1 ***
期待値:hoge5
実測値:hoge
*** value2 ***
期待値:huga5
実測値:huga
*** value3 ***
期待値:hogehuga5
実測値:hogehuga
===== データ:6 =====
*** id ***
期待値:009
実測値:データなし
*** value1 ***
期待値:hoge9
実測値:データなし
*** value2 ***
期待値:huga9
実測値:データなし
*** value3 ***
期待値:hogehuga9
実測値:データなし
##### 相互参照:実測値->期待値 #####
OK

コメント

タイトルとURLをコピーしました