Javaにおけるユニットテスト、XML、アノテーションの基礎

ユニットテスト

ユニットテストは、ソフトウェアの最小機能単位に対してテストコードを記述する手法です。Javaでは最小機能単位はメソッドであるため、ユニットテストはJavaメソッドの正確性を検証するために使用されます。

  • 従来の問題点: mainメソッド内でのテストは、一つのメソッドが失敗すると他のメソッドのテストに影響を及ぼします。
  • JUnitの利点:
    • テストメソッドを柔軟に選択して実行でき、一括実行も可能です。
    • 特定のテストメソッドが失敗しても、他のテストには影響しません。
    • 成功時は緑色、失敗時は赤色で結果が表示されます。

クイックスタート

JUnitでテストするメソッドは、public、引数なし、戻り値なしである必要があります。

1. JARファイルを手動でインポートするか、ネットワーク環境があればプロンプトに従ってインポートします。
2. テスト対象のメソッドに @Test アノテーションを付与します。
3. 実行結果が緑色(成功)または赤色(失敗)で表示されます。

XMLの導入

XMLは設定ファイルとして使用され、データを柔軟に読み込み、変更することで結合度を低下させることができます。

設定ファイルの種類

  • Properties: 一対一のデータ保存に適しています(例:username=root, password=123456)。
  • XML: 一対多のデータ保存に適しています。

XMLの概要

XML(Extensible Markup Language)は、拡張可能なマークアップ言語です。

  • マークアップ言語: タグを使ってデータを記述する言語です。タグは「要素」とも呼ばれます。
  • 拡張可能: タグの名前を自分で定義できます。
利点
  • ソフトウェアの設定ファイルとして使用できます。
  • データの保存や転送に使用できます。特にそのフォーマットが好まれます。

XMLの文法

ルール
  • 作成: XMLファイルを作成し、拡張子は .xml にします(例:hello_world.xml)。
  • 文書宣言: 文書宣言は必ず1行目、1列目に記述します。
    <?xml version="1.0" encoding="UTF-8" ?>
    • version: 必須属性です。
    • encoding: 省略可能です。XMLファイルを開く際の文字コードを指定します(通常はUTF-8)。
    • standalone: 省略可能で、XMLファイルが他のXMLファイルに依存するかを示します(yes/no)。
  • タグのルール:
    • ルートタグは必須で、1つだけ存在します。
    • タグは山括弧と有効な識別子で構成されます。
      <student>
    • タグは対で使用します。
      <student> </student>(開始タグと終了タグ)
    • 特殊なタグは対でなくても良いが、終了マークが必要です。
      <address/>
    • タグには属性を定義でき、属性とタグ名はスペースで区切り、属性値は引用符で囲みます。
      <student id="1"> </student>
    • タグは正しくネストする必要があります。
      正しい例:
      <student id="1"> <name>张三</name> </student>
      誤った例:
      <student id="1"> <name>张三 </student> </name>
  • 詳細:
    • コメントは <!-- コメント --> で記述します。
    • 特殊文字はエスケープシーケンスを使用します。
      &lt; は <、&gt; は >、&amp; は &、&apos; は '、&quot; は " を表します。
    • CDATAセクションを使用すると、任意の文字を記述できます。
      <![CDATA[ ... 内容 ... ]]>
/*
* 要件: 都市とその区を表すXMLファイルを作成する
* 都市: city
* 区: area
*/

XMLの制約(概要)

制約は、XMLファイルで使用可能なタグや属性を制限するために使用されますが、実際に自分で記述することは稀です。

種類
  • DTD制約
  • Schema制約
DTD制約
記述手順
  1. 拡張子が .dtd のファイルを作成します。
  2. XMLファイルで使用する要素を確認します。
    <!ELEMENT> で要素を定義します。
  3. 要素が単純要素か複合要素かを判断します。
    単純要素:子要素を持たない
    複合要素:子要素を持つ
コード例
<!ELEMENT persons (person)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
DTDの導入方法
  • ローカルのDTDを導入
    <!DOCTYPE persons SYSTEM "persondtd.dtd">
  • XMLファイル内に直接記述
    <!DOCTYPE persons [<!ELEMENT person (name,age)> ... ]>
  • ネットワーク上のDTDを導入
    <!DOCTYPE persons PUBLIC "名称" "URL">
Schema制約

SchemaとDTDの違いは以下の通りです。

  1. SchemaファイルもXMLファイルであり、XML文法に従い、拡張子は .xsd です。
  2. 1つのXMLファイルに複数のSchema制約を参照でき、名前空間(Javaのパッケージ名に類似)で区別します。
  3. DTDの要素のデータ型は主にPCDATAですが、Schemaは多くのデータ型をサポートします。
  4. Schemaの文法はより複雑です。
Schema制約の記述
1. 拡張子が .xsd のファイルを作成します。
2. 文書宣言を定義します。
3. Schemaファイルのルートタグは <schema> です。
4. <schema> に xmlns="http://www.w3.org/2001/XMLSchema" を定義します。
5. <schema> に targetNamespace=一意のURLアドレス を定義し、現在のSchemaファイルの名前空間を指定します。
6. <schema> に elementFormDefault="qualified" を定義し、現在のSchemaファイルが品質の良いファイルであることを示します。
7. element で要素を定義します。
8. 要素が単純要素か複合要素かを判断します。
Schemaの導入例
<stus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://www.mhys.com"
      xsi:schemaLocation="http://www.mhys.com stus.xsd">
    <student>
        <name>张三</name>
        <age>23</age>
    </student>
</stus>

XMLの解析

解析方法
  • SAX解析
  • DOM解析
準備
  1. dom4j-1.6.1.jar をインポートします。
  2. Documentオブジェクトを取得します。
SAXReader reader = new SAXReader();
Document document = reader.read(new File("day15-code\\src\\xml\\stus.xml"));
System.out.println(document);
サンプルコード
package com.example.start;

import com.example.domain.Student;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) throws DocumentException {
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File("mC\\src\\xml\\stus.xml"));

        List<Student> studentList = new ArrayList<>();

        // 1. ルートタグを取得
        Element root = document.getRootElement();

        // 2. ルートタグのすべての子タグを取得
        List<Element> students = root.elements("student");

        // 3. コレクションをループ
        for (Element elem : students) {
            // 4. タグの属性を取得
            String id = elem.attributeValue("id");
            // 5. nameタグの値を取得
            String name = elem.element("name").getText();
            // 6. ageタグの値を取得
            String age = elem.element("age").getText();
            // 7. Studentオブジェクトにカプセル化
            Student student = new Student(name, Integer.parseInt(age));
            // 8. コレクションに追加
            studentList.add(student);
        }

        studentList.forEach(s -> System.out.println(s));
    }
}

アノテーション

概要

アノテーション(Annotation)はJDK 1.5の新機能で、プログラムに注釈を付けるために使用されます。

  • コメントは人間向け、アノテーションは仮想マシン向けです。
  • アノテーションを使用してクラスに追加情報を提供できます。
  • アノテーションはコンパイラやJVMに情報を伝え、それに応じた機能を実行させます。

JDKの一般的なアノテーション

  • @Override: メソッドのオーバーライドを示します。
  • @Deprecated: 修飾されたメソッドが非推奨であることを示します。
  • @SuppressWarnings("all"): 警告を抑制します。

サードパーティのフレームワークでもアノテーションが提供されています。例:JUnit

  • @Test: テストメソッドを実行します。
  • @Before: Testの前に実行され、初期化を行います。
  • @After: Testの後に実行され、後処理を行います。

カスタムアノテーション(概要)

カスタムアノテーションは単体では意味がなく、通常はリフレクションと組み合わせて使用します。

public @interface アノテーション名 {
    public 属性の型 属性名 () default デフォルト値;
}

public @interface Anno {
    String show() default "show...";
}
属性の型
  • 基本データ型
  • String
  • Class
  • アノテーション
  • 列挙型
  • 上記の型の一次元配列
public @interface MyAnno {
    String show1() default "show1";
    int show2() default 132;
    MyAnno2 show3() default @MyAnno2;
    Class show4() default String.class;
    int[] show5() default {1, 2, 3};
}

アノテーションの使用(習得推奨)

  • クラス
  • メソッド
メンバ変数への適用は稀です。
// アノテーションの属性にデフォルト値がない場合は、手動で値を指定する必要があります。
@Anno(name="张三")
  • 配列の属性値が1つだけの場合、{} を省略できます。
特別な属性(習得推奨)
  • 複数の属性に値が代入されていない場合は、使用時にすべての属性に値を代入する必要があります。
  • 属性が1つだけで、その名前が value の場合、使用時に属性名を省略して値を直接指定できます。
@Anno("valueに代入")
  • 要件: カスタムアノテーション @Test を作成し、クラスのメソッドに付与します。アノテーションが付与されたメソッドのみを実行します。
  • 実装手順:
    1. カスタムアノテーション @Test を作成し、クラスの特定のメソッドに付与します。
    2. テストクラスで、アノテーションが付与されたクラスのClassオブジェクトを取得します。
    3. クラスのすべてのメソッドオブジェクトを取得します。
    4. 各メソッドオブジェクトをループし、対応するアノテーションが存在するかを確認します。
// @Testアノテーションの生存期間を指定
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Test {
}

public class UseTest {
    public void show(){
        System.out.println("UseTest....show....");
    }

    @Test
    public void method(){
        System.out.println("UseTest....method....");
    }

    @Test
    public void function(){
        System.out.println("UseTest....function....");
    }
}

public class AnnoDemo {
    public static void main(String[] args) throws Exception {
        // 1. リフレクションでUseTestクラスのClassオブジェクトを取得
        Class clazz = Class.forName("com.example.myanno3.UseTest");
        UseTest useTest = (UseTest) clazz.newInstance();

        // 2. リフレクションでクラス内のすべてのメソッドオブジェクトを取得
        Method[] methods = clazz.getMethods();

        // 3. 配列をループ
        for (Method method : methods) {
            // isAnnotationPresentでメソッドに指定アノテーションが存在するか確認
            if(method.isAnnotationPresent(Test.class)){
                method.invoke(useTest);
            }
        }
    }
}

メタアノテーション(概要)

  • 概要: メタアノテーションはアノテーションを説明するためのアノテーションです。
  • 種類:
メタアノテーション名説明
@Targetアノテーションが使用できる場所を指定します。
@Retentionアノテーションの生存期間(ライフサイクル)を指定します。
@Target

@Target はアノテーションが使用できる位置を指定します。指定がない場合、任意の場所で使用できます。
使用可能な値は ElementType 列挙クラスで定義されています。

  • TYPE: クラス、インターフェース
  • FIELD: メンバ変数
  • METHOD: メンバメソッド
  • PARAMETER: メソッドのパラメータ
  • CONSTRUCTOR: コンストラクタ
  • LOCAL_VARIABLE: ローカル変数
@Retention

@Retention はアノテーションの生存期間を指定します。
使用可能な値は RetentionPolicy 列挙クラスで定義されています。

  • SOURCE: アノテーションはソースコード段階のみ有効で、生成されたバイトコードファイルには含まれません。
  • CLASS: アノテーションはソースコードとバイトコードファイル段階で有効ですが、実行時には無効になります(デフォルト値)。
  • RUNTIME: アノテーションはソースコード、バイトコードファイル、実行時のすべての段階で有効です。

タグ: JUnit XML アノテーション Java dom4j

6月20日 00:33 投稿