2
0

JUnitのテストケースにおけるパターン表の管理

Last updated at Posted at 2023-12-05

この記事は BABY JOB Advent Calendar 2023 の 6 日目の記事です。

まえおき

久しく投稿してなかったが、会社でアドベントカレンダーなる祭典を教えてもらい、乗っかってみる。

今回はJUnitにおけるパターン網羅の方法。
ではなく、パターン網羅したことをどのように残すかについて考えたので、披露したい。

今まで様々なプロジェクトに携わってきたが、こういった議論は一度もなかった。
もしかしたら、開発史上初の試みなのかもしれない。
そうなのであれば、私は喜んでそのパイオニアとなろう。
ただ、既に議論され尽くしていても、そっとしおいてほしい。
そして、パイオニア気分に浸らせたままにしてほしい。

問題提起

さて、このほど新しい環境で新しいプロジェクトに関わることになった。
そこでは、アジャイル開発が行われ、CICDが取り入れられて、モダンな開発が行われていた。
その中では当然単体テストツールによるテストがあるのだが、これがなかなか多い。
そして、パターン表などが残っていないため、コードから読み取る以外方法なない。
ここで考えた。
果たして、単体テストツールにおいてパターン表をどのように残すべきか?
思いつくものとしては以下のものだろう。

  • Excel等でパターン表を作成し、GoogleドライブやSVNで管理する
  • Excel等でパターン表を作成し、Gitで管理する
  • テストクラスファイル中になんとかして残す

先2つについては、テストクラスファイルとファイルが分かれてしまうため、パターン表があることに気づかず、メンテナンスされない可能性がある。
そのため、Javadoc等にその情報の記載が必要だ。
また、テストクラスファイルとは別の場所で管理されているため、SVNやGoogleドライブ等の管理に依存してしまう。
(適切にバージョン管理されているのか、差分がきちんと管理できるのかなど)

かく言う私も今まではJavaコードをGitLab、パターン表をExcelで作成し、SVNで管理していた。
(先述した一つ目の選択肢を取っていた)
しかし、そこには以下のような課題があった。

  • Javadocに@see<a href="xxxx">でパターン表との紐付けをしていても、メンテナンスがされないことがあった
  • パターン表がExcelのため、SVNでどこを修正したのかが分かりづらかった
  • Microsoft Officeがメンバー分必要

そこで、私は最後のテストクラスファイル中になんとかして残す方法を考えた結果、JavadocにHTMLのTableタグで表を残すことにした。
こうすることで、先に私が直面した3つの課題を以下のようにクリアできると考えた。

  • Javadocにパターン表があるため、別途ファイルを探さなくてよい
  • Javadocへの記載のため、テキストベースで差分を比較できる
  • Microsoft Officeに依存せず、どの環境でも確認ができる

アプローチ

さて、本題である。
Javadoc上にHTMLのTableタグを残すとして、Javadoc上でのメンテナンスは少々面倒である。
そこで、会社で支給されているGoogle Workspaceを活用し、Javadoc上にTableタグを残すためのツールを手軽に作成しようと思う。
ただし、私はGoogle App Script(GAS)はほぼ触ったことがないため、ChatGPTを活用することとする。

まずは、ChatGPTに対して、以下のようなことを問いかける。

GASで以下の条件を満たすコードを作成して。
・A1セルからヘッダー行、データ行のあるHTMLのTableタグを取得する
・取得したTableタグを分解してスプレッドシートに書き込む
・関数はボタンを押したら実行される

すると、すぐに下記のコードを作成してもらえた。

function importTableFromHTML() {
  // スプレッドシートを取得
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();

  // A1セルの値を取得
  var cellValue = sheet.getRange("A1").getValue();

  // HTMLからTableタグを正規表現で抽出
  var tableRegex = /<table[\s\S]*?<\/table>/i;
  var tableMatch = cellValue.match(tableRegex);

  if (tableMatch) {
    // 抽出したTableタグを分解して2次元配列に変換
    var tableHtml = tableMatch[0];
    var table = parseTable(tableHtml);

    // スプレッドシートに書き込む
    writeTableToSheet(table);
  } else {
    Logger.log("Table not found in the specified cell (A1).");
  }
}

// Tableタグを分解して2次元配列に変換する関数
function parseTable(tableHtml) {
  var table = [];
  var tableRegex = /<tr[\s\S]*?<\/tr>/gi;
  var rowMatches = tableHtml.match(tableRegex);

  if (rowMatches) {
    for (var i = 0; i < rowMatches.length; i++) {
      var rowHtml = rowMatches[i];
      var cellRegex = /<t[hd][\s\S]*?<\/t[hd]>/gi;
      var cellMatches = rowHtml.match(cellRegex);
      var row = [];

      if (cellMatches) {
        for (var j = 0; j < cellMatches.length; j++) {
          var cellHtml = cellMatches[j];
          var cellText = cellHtml.replace(/<[^>]*>/g, "");
          row.push(cellText);
        }
      }

      table.push(row);
    }
  }

  return table;
}

// 2次元配列のデータをスプレッドシートに書き込む関数
function writeTableToSheet(table) {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();

  // データをクリア
  sheet.clear();

  // データを書き込む
  for (var i = 0; i < table.length; i++) {
    var row = table[i];
    sheet.getRange(i + 1, 1, 1, row.length).setValues([row]);
  }

  Logger.log("Table imported successfully.");
}

うむ、動きそうだ。
とりあえず、Javadoc→スプレッドシートに関してはこれで良いとしよう。
では、この逆も作成してもらおう。

スプレッドシートの情報をhtmlのTableタグに変換してA1セルに出力するGASを作成して。

とお願いすると

function exportTableToHTML() {
  // スプレッドシートを取得
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getActiveSheet();

  // データを取得
  var data = sheet.getDataRange().getValues();

  // HTMLのTableタグに変換
  var htmlTable = convertToHTMLTable(data);

  // A1セルにHTMLを出力
  sheet.getRange("A1").setValue(htmlTable);

  Logger.log("Table exported to HTML successfully.");
}

// 2次元配列のデータをHTMLのTableタグに変換する関数
function convertToHTMLTable(data) {
  var htmlTable = "<table border='1'>";

  for (var i = 0; i < data.length; i++) {
    htmlTable += "<tr>";

    for (var j = 0; j < data[i].length; j++) {
      htmlTable += "<td>" + data[i][j] + "</td>";
    }

    htmlTable += "</tr>";
  }

  htmlTable += "</table>";

  return htmlTable;
}

うむ、これもいい感じだ。
あとは、スプレッドシートで1シートでI/Oさせるのか、HTMLシート/Tableシートに分けるのかで使い方を変えれば、良いかな。

まとめ

今回は、HTML→スプレッドシート、スプレッドシート→HTMLの部分のみを作成した。
ただ、実際コードから取得するのであれば、Javadocなどのものをそのまま貼り付けたいところなので、そこはまたどこかの機会でやるとします。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0