0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

チャットbotお試し用アプリ開発_22日目_エスケープ処理の単体テスト

Last updated at Posted at 2025-08-02

目次

・本日の成果・考え
・最後に

本日の成果

コントローラークラスのPGの際に、記載だけしてテストしてなかったエスケープ処理のUTを行いたいと思います。

先にUTしておけよと自分ながら思います。
テスト方針としては、

  1. エスケープされた文字列をアサート。
  2. エスケープ後の文字列がHTMLファイルでJavaScriptとして認識されるか
    の上記2つを考えています。
    ※CommonFunctionのソースだけでは、エスケープ結果が想定通りかは確認できても、エスケープした結果がJavaScriptとして正しい処理なのかまでは確認できないからです。
    LTのタイミングでも良いかもですが、面倒なのでこのタイミングで良いと思いました。

ソース

CommonFunction.java

/**
	 * Java→JavaScriptへのエスケープ処理
	 * @param input 文字列型のチェック対象
	 * @return input エスケープ処理済み
	 */
	public static String escapeForJS(String input) {
	    if (input == null) return "\"\"";
	    String escaped = input
	        .replace("\\", "\\\\") //バックスラッシュ2つ
	        .replace("\"", "\\\"") //バックスラッシュ1つ
	        .replace("\n", "\\n") //改行\n
	        .replace("\r", "\\r") //改行CR
	        .replace("'", "\\'") //シングルクォーテーション
	        .replace("\t", "\\t"); //タブ
	    return "\"" + escaped + "\"";  // JS文字列として囲う
	}

テストソース

escapeForJSTest.java
	/**
	 * escapeForJS
	 * エスケープ処理
	 */
	@Test
	public void testEscapeForJS() {
		String className = new Object() {
		}.getClass().getName();
		String resultOutput = className + "のtestEscapeForJSメソッドのテスト";
		out.println("**********************************************");
		out.println(resultOutput + "が開始されました。");
		try {
			//通常文字列 
			String abc = CommonFunction.escapeForJS("abc");
			System.out.println("パターン1.abc:"+abc);
			//バックスラッシュ1つ
			String abc2 = CommonFunction.escapeForJS("a\"b\"c");
			System.out.println("パターン2.abc2:"+abc2);
			//シングルクォーテーション
			String abc3 = CommonFunction.escapeForJS("a'b'c");
			System.out.println("パターン3.abc3:"+abc3);
			//改行・CR
			String abc4 = CommonFunction.escapeForJS("a\r\nb");
			System.out.println("パターン4.abc4:"+abc4);
			//タブ
			String abc5 = CommonFunction.escapeForJS("a\tb");
			System.out.println("パターン4.abc5:"+abc5);
			//改行+文字列
			String line = CommonFunction.escapeForJS("line1\nline2");
			System.out.println("パターン5.line:"+line);
			//バックスラッシュ2つ
			String test = CommonFunction.escapeForJS("\\\\test");
			System.out.println("パターン6.test:"+test);
			//日本語(全角)
			String hello = CommonFunction.escapeForJS("こんにちは?");
			System.out.println("パターン7.hello:"+hello);
			
			assertEquals("\"abc\"", abc);
			assertEquals("\"a\\\"b\\\"c\"",abc2 );
			assertEquals("\"a\\'b\\'c\"", abc3);
			assertEquals("\"a\\r\\nb\"", abc4);
			assertEquals("\"a\\tb\"", abc5);  
			assertEquals("\"line1\\nline2\"", line);
			assertEquals("\"\\\\\\\\test\"", test);
			assertEquals("\"こんにちは?\"", hello); // 全角記号
			out.println(resultOutput + "が正常終了しました。");
		} catch (Exception e) {
			String resultError = String.format("エラーが発生しました。内容は{%s}", e);
			out.println(resultError);
			fail();
		} finally {
			out.println(resultOutput + "が終了しました。");
			out.println("**********************************************");
		}
	}

テスト結果

スクリーンショット 2025-08-02 10.07.40.png

**********************************************
app.test.CommonFunctionTest$10のtestEscapeForJSメソッドのテストが開始されました。
パターン1.abc:"abc"
パターン2.abc2:"a\"b\"c"
パターン3.abc3:"a\'b\'c"
パターン4.abc4:"a\r\nb"
パターン4.abc5:"a\tb"
パターン5.line:"line1\nline2"
パターン6.test:"\\\\test"
パターン7.hello:"こんにちは?"
app.test.CommonFunctionTest$10のtestEscapeForJSメソッドのテストが正常終了しました。
app.test.CommonFunctionTest$10のtestEscapeForJSメソッドのテストが終了しました。
**********************************************

エスケープ処理の動きは想定通りであることが確認できました。

調査用HTML

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>エスケープ文字列テスト</title>
  <style>
    body { font-family: sans-serif; padding: 20px; }
    .message { background:white; margin: 5px 0; padding: 6px; border-radius: 4px; white-space: pre-wrap; }
  </style>
</head>
<body>

  <h2>JS側での文字列解釈テスト</h2>
  <div id="chatArea"></div>

  <script>
    const chatArea = document.getElementById("chatArea");

    function appendMsg(chunk) {
      const msg = document.createElement("div");
      msg.className = "message";
      msg.textContent = chunk;
      chatArea.appendChild(msg);
    }
    function showError(msg, error) {
      const chatArea = document.getElementById("chatArea");
      const errDiv = document.createElement("div");
      errDiv.className = "message error";
      errDiv.textContent = `[ERROR] ${msg}\n${error.message}`;
      chatArea.appendChild(errDiv);
    }

    // Javaの escapeForJS によって加工された文字列リスト(Java側からコピー貼り付け)
    const escapedStrings = [
      "abc",
      "a\"b\"c",
      "a\'b\'c",
      "a\r\nb",
      "a\tb",
      "line1\nline2",
      "\\\\test",
      "こんにちは?",
    ];

    escapedStrings.forEach((str, index) => {
      try {
        appendMsg(`パターン${index + 1}: ${str}`);
      } catch (e) {
        showError(`パターン${index + 1}でエラー`, e);
      }
    });
  </script>
</body>
</html>

不正な文字を混ぜるとJacaScript自体がエラーとなって、正常なものも表示できませんでした。ですので、単体テスト結果以外の不正文字を混ぜることはできませんでした。

補足として、どうして
assertEquals("\"a\\r\\nb\"", abc4);がHTMLのリストで「"a\r\nb"」かというと、

WindowController.java
	/************
	* メソッド名:受信チャンク表示
	* 処理内容:受信したチャンク毎に表示処理を呼び出す
	* @param chunk Difyからのレスポンス
	/************/
	private void appendChatChunk(String chunk) {
		webEngine.call("appendMsg("+ CommonFunction.escapeForJS(chunk)+")");

実際の呼び出し時には、一度Javaの文字列としてcallメソッドに渡しており、
その時の内容はさっきのエスケープ処理で出力した形式と同じになっております。
呼び出し時の挙動
call("appendMsg("a\r\nb")";

画面として出力

以下の拡張機能を使いました。
スクリーンショット 2025-08-02 10.47.45.png

結果

スクリーンショット 2025-08-02 11.21.13.png

当然、問題なしですね笑。まあ一応テストの結果が、JavaScriptでも正しく読める形式になっていることは確認できたかと。

最後に

ここまでお付き合いありがとうございます。

前回から1週間ほどあきましたが、少しずつやっていこうと思います。
私ごとですが、前回の動作確認の様子を動画にして上長に共有しています。
感触としては良好で、あとはGoもらえば本格的に動き出せそうです。

それまでに、アプリの動作テストと、本番稼動の端末(Windows端末)への導入方法を確立させないとですね。

以上、ありがとうございました。

0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?