記事ディレクトリ
すべての知識システムの記事はGitHubに含まれています、スターへようこそ!
GitHubアドレス: https ://github.com/Ziphtracks/JavaLearningmanual
WeChatパブリックアカウント「CodeOutOffer」を検索してフォローすると、ブラザーZが学習福祉リソースをお送りします。
Junitユニットテスト
1.ユニットテストとは何ですか?
コンピュータプログラミングでは、ユニットテスト(英語:ユニットテスト)は、モジュールテストとも呼ばれ、プログラムモジュール(ソフトウェア設計の最小ユニット)の正確性を検証するためのテストです。プログラムユニットは、アプリケーションのテスト可能な最小の部分です。簡単に言えば、データの安定性がプログラムの期待を満たしているかどうかをテストすることです。
第二に、ユニットテストの重要性
テストと言えば、なぜプログラムをテストする必要があるのでしょうか。テストはプログラムにどのようなメリットをもたらしますか?
まず、私たち一人一人が間違いを犯します。結局のところ、人々は完璧ではありません。プログラムで間違いを犯すのは、人生で間違いを犯すようなものです。間違いは1、2日で発生しません。変更が必要な場合、短時間で変更することはできません。ここで話したプログラムのエラーは有名なバグです。
誤って間違える可能性がありますが、最終段階でプロジェクトの結果を確認したところ、エラーが発生した場合、現時点ではバグの原因を特定することは困難です。間違いがステップエラーにつながる可能性があることは誰もが知っています。
ただし、上記のステートメントでは、テストが特に重要です。テストの概念では、プロジェクトの小さなモジュールを終了するときに、最初に小さなモジュールが正しいか期待を満たしているかどうかをテストします。間違っているか期待を満たしていない場合は、正しいか期待を満たしているまで繰り返し変更する必要があります。ここで私が言ったことは、ユニットテストの使用です。
テストを1つずつ終了し、1つずつテストすると、アイテムがパズルのようにまとめられていることがわかります。簡単に言えば、これがユニットテストの重要性です。
免責事項:用語はあまりにも鈍いようです、言葉はあなたに理解させるかもしれません、私の言葉を許してください!ありがとうございました!
3つ、ブラックボックステストとホワイトボックステスト
3.1ブラックボックステスト
ブラックボックステストは、機能テストとも呼ばれます。テストを通じて、プログラムが正常に使用できるかどうかを確認します。テスト中、プログラムを開けられない箱と見なし、暗闇の中で何も見えず、内部コードの書き方もわかりませんでした。つまり、内部構造やパフォーマンスを考慮せずにプログラムのパラメータを入力し、プログラムの出力(出力)が正常範囲内にあるかどうかを確認します。通常、現時点では、結論を出すためにさらにテストが必要です。
機能:コードの記述に参加する必要はありません。パラメーター値を渡した後、プログラムが正常であるか、期待値に達しているかを確認してください。
3.2ホワイトボックステスト
ホワイトボックステストは、構造テストとも呼ばれます。ここで、ホワイトボックステストはブラックボックステストとは異なります。テストプロセス中、プログラムは見える白い透明なボックスと見なすことができます。ボックス内のコードと構造はわかっています。ホワイトボックステストを使用する場合、テスターはプログラムの内部構造をチェックし、プログラムのロジックをチェックすることから始め、入力パラメーター(入力)をチェックし、プログラムの実行プロセスと出力(出力)の結果を段階的に確認する必要があります。最後に、テストデータを取得します。これが「ホワイトボックステスト」が網羅的パステストと呼ばれる理由です。これも、すべての構造の正確性と期待値をチェックするためのプログラムの内部構造とコードを知っているためです。
注:ユニットテストは、ホワイトボックステストの一種です。
第四に、ユニットテストのアイデアの転送
ここでは、ユニットテストを忘れ、独自のテストの通常の方法を使用してデータをテストし、その欠点を確認します。
まず、計算機クラスを作成し、その中に2つの計算メソッドを作成して、シミュレーションとテストを行いました。
package com.mylifes1110.java;
/**
* 计算器
*/
public class Calculator {
/**
* 加法
*/
public int add(int num1, int num2) {
return num1 + num2;
}
/**
* 减法
*/
public int cut(int num1, int num2) {
return num1 - num2;
}
}
次に、テストクラスを作成し、オブジェクトを作成して、最初に追加をテストします。
package com.mylifes1110.java;
public class Test {
public static void main(String[] args) {
Calculator calculator = new Calculator();
//测试加法
System.out.println(calculator.add(10, 10)); //20 正确
}
}
テスト後、結果が正しいことを確認し、次のテストに進みます。テストするデータが2つあるため、通常は1つのデータをテストした後、次のテストに進む前に、テストしたデータをコメントアウトする必要があります。次のように:
package com.mylifes1110.java;
//测试类
public class Test {
public static void main(String[] args) {
Calculator calculator = new Calculator();
//测试加法
// System.out.println(calculator.add(10, 10)); //20 正确
//测试减法
System.out.println(calculator.cut(10, 10)); //0 正确
}
}
2つのデータをテストした後、プロジェクトコードの記述を続けます。
実際、これは面倒だと思いましたか?前のステップでテストしたデータをコメントアウトする必要があるのはなぜですか?
答えはここにあります。本当に面倒です。コメントアウトされている理由は、プロジェクトコードを作成するときにテストする必要があるためです。同じテストクラスでこれほど多くのデータをテストすることは不可能です。また、テストされたプログラムでは、データとデータは関連しており、相互に影響を及ぼします。これにより、テストが不正確になり、その後のコーディングの進行状況とプロジェクトの精度に影響します。
上記のテストの欠点を知っているので、ユニットテストの概念も理解する必要があります。上記のテストの問題を解決するために、ユニットテストにはどのような特性が必要ですか?実際、私たちのユニットテストもコーディング標準によって制約されています。コーディング基準については、第5章に進んでみませんか?
5つのユニットテストコーディング標準
ユニットテストにはいくつかのコーディング標準があるので、小さな本を持って書き留めましょう。
- クラス名:テストクラスを定義し
被测试类名Test
ます。クラス名はで構成されます。例:CalculatorTest- パッケージ名:定義されたテストクラスを
xxx.xxx.xxx.test
パッケージに配置する必要があります。例:package com.mylifes1110.test;- メソッド名:メソッド名テストメソッドdefine
test测试方法
と测试方法
。には2つの方法があります。例:testAddおよびadd- 戻り値:このメソッドはクラスでのみテストされ、独立して実行できるため、戻り値を処理する必要がないため、ここで使用します
void
。例:public void add();- パラメータリスト:私たちの方法はテストに使用されるため、パラメータリストの入力は必要ありません。テストするとき、テストに必要なパラメーターを渡すことができます。これがパラメータリスト
空
です。例:例:public void add();- @Testアノテーション:完了するにはテストを実行する必要があります。主な方法が1つしかない場合でも、構造内でテスト済みの方法をコメントアウトする必要があることは明らかです。この問題を解決するには、テストメソッドの上に
@Test
注釈を追加してテストを完了する必要があります。注釈が追加されている限り、このメソッドを個別に実行してテストを完了することができます。- @TestアノテーションjarパッケージJunit4、5: @Testアノテーションでは、使用するjarパッケージをインポートする必要があります。2つのjarパッケージがあります:
junit-4.13-rc-2
とhamcrest-core-1.3
。ここでは、Junit4、ユニットテスト、およびJunit5を使用していますが、バージョンの違いがわかりませんでした。主な理由は、テストを完了できることです。- IDEAはすぐにJunit4と5をインポートしました: IDEAを使用している友達、あなたの福音はここにあります。最初にテストクラスとメソッドを
@Test
作成してから、テストメソッドの上に注釈を追加できます。このとき、IDEAによって表示される@Test注釈は赤です。このとき、Alt + Enter
キーの組み合わせを使用してインポートJunitユニットテストリストを開き、Junit4またはJunit5を選択して確認します。インポートは成功しました!このとき、注釈を確認してください。赤みはありません。
6、@ TestテストおよびAssertアサーションステップ
アサーション方式 | 説明 |
---|---|
assertNull(java.lang.Objectオブジェクト) | オブジェクトが空かどうかを確認します |
assertNotNull(java.lang.Objectオブジェクト) | オブジェクトが空でないかどうかを確認します |
assertEquals(長い期待、長い実際) | ロングタイプの値が等しいかどうかを確認します |
assertEquals(2倍の期待値、2倍の実績、2倍のデルタ) | 指定された精度のdouble値が等しいかどうかを確認します |
assertFalse(ブール条件) | 条件が偽かどうかを確認します |
assertTrue(ブール条件) | 条件が真であるかどうかを確認します |
assertSame(java.lang.Objectが必要です、java.lang.Objectが実際です) | 2つのオブジェクト参照が同じオブジェクトを参照しているかどうか(つまり、オブジェクトが等しいかどうか)を確認します |
assertNotSame(java.lang.Object予期しない、java.lang.Objectactual) | 2つのオブジェクト参照が統合オブジェクトを参照していない(つまり、オブジェクトが等しくない)かどうかを確認します |
まず、次のように、Junitユニットのテスト仕様に従ってテストコードを記述します。
次に、各メソッドの左側に、テストが必要な小さな緑色の三角形があり、ユニットテスト操作に使用されていることがわかります。つまり、特定のメソッドを実行してテストすることしかできません。add()メソッドを実行すると、結果は次のようになります。
このとき、コンソールが緑色で出力が印刷されていることがわかりました。これは、プログラムが正常であることを示しています。算術例外を追加するとどうなりますか?次のように:
ここで、コンソールが赤に変わり、エラーメッセージが表示されることがわかります。これは、プログラムのテスト後に問題が発生したことを示しています。これは、プログラムの正しさと失敗の関係にすぎません。
期待値が必要な場合はどうなりますか?その場合、テストの結果は私が望む期待値ではありませんが、プログラムはまだ緑色です。プログラムに問題がないことが証明された場合はどうすればよいですか?印刷コンソールで情報を確認したと言う友人もいますが、印刷結果が期待値でない場合は、プログラムに問題があり、修正が必要なことを意味します。はい、それを言っても問題はありません。しかし、私たちが開発しているときに、あなたの怠慢や疲労のために緑色が表示された場合はどうすればよいですか?したがって、この問題に直面して、ユニットテストでは期待値を印刷しないようにしています。緑と赤の方が優れていることに注意する必要があります。プログラムの精度を直接反映して期待値を達成できます。
このとき、オブジェクトの静的メソッドを導入して、それが期待値であるかどうかをアサートする必要があります。
Assert.assertEquals(预期值, 结果);
この時点で、Assert期間から出るメソッドは、配列と共通のデータタイプの両方をアサートできることがわかりました。したがって、現時点では、これを使用して期待値をアサートします。次のように:
現時点では、結果の期待値は10であると断言します。アサーション後、期待値に達しない場合はエラーが報告されます!
注:アサーションを使用するときは、Doubleオブジェクトをアサーションしないようにしてください。倍精度の数値の場合、浮動小数点の丸めの問題を回避するために、増分比較を使用することが絶対に必要です。パラメータassertEquals
付きのdouble
3パラメータバージョンを使用する場合。
assertEquals(double expected, double actual, double delta);
このようにDouble
、ボクシングは自動的にキャンセルされ、double
すべてが正常であるため、テスト結果は失敗しません。それ以外の場合、2つのパラメーターを使用してdouble型をアサートすると、次のエラーメッセージが表示されます。
セブン、@ Beforeおよび@Afterアノテーション
上記のとおりですが、繰り返し操作がありますか?たとえば、各メソッドは新しいオブジェクトに移動する必要があります。賢い友達の中には、メソッドと同じレベルでクラスに入れることができると言う人もいます。はい、このアプローチも前向きな解決策です。
しかし、Junitユニットテストでは、リソースアプリケーションとして使用される@Beforeアノテーションがあります。つまり、@ Beforeアノテーションで変更されたメソッドは、テストメソッドの前に自動的に実行されます。したがって、オブジェクトを作成するプロセスを初期化するinitメソッドを定義できます。これは@Beforeアノテーションが行うことです!
IOストリームの読み取りおよび書き込み操作など、一部のアプリケーションシナリオ。このコードをテストする場合は、ストリームを閉じるプロセスが必要です。ストリームを閉じ、finallyブロックを使用して、最終ストリームの閉じ操作を確認します。現時点では、Junitユニットテストに@Afterアノテーションがあり、リソースを閉じるために使用されます。つまり、@ Afterアノテーションで変更されたメソッドは、テストメソッドの後に実行されます。したがって、リソースが最終的に閉じられて破棄されることを確認する必要がある場合は、リソースを閉じたり破棄したりするためのcloseメソッドを定義できます。これは@Afterアノテーションが行うことです!
注: @Beforeおよび@Afterアノテーションは、プログラムがエラーを報告したときにデータの初期化とシャットダウンを保証できます。2つのメソッドは引き続き実行されます。これは、tomactサーバーの初期フェーズと破棄フェーズに少し似ており、それらの実行はまったく影響を受けません。
8. @MyTestアノテーションをカスタマイズして、ユニットテストを実装します
目的:カスタム注釈@MyTestを完成させ、注釈でマークされたメソッドを実装して開始します。(ユニットテストを実行するには、@ Testアノテーションを模倣します)
手順:
- MyTestという名前の新しい注釈クラス(annotation)を作成します
- TestJunitユニットテストクラスを作成し、次のようないくつかのメソッドを記述します。
public void test1()
- MyTestDemoテストクラス(メイン関数実装クラス)を作成します。このクラスは主にリフレクションメカニズムを使用して、TestJunitユニットテストクラスで@MyTestアノテーションメソッドの開始を実現します。
- アノテーションクラスのライフサイクルはリフレクションメカニズムと一致しています。つまり、定義されたアノテーションは実行時まで保持でき、アノテーション情報はリフレクションメカニズムを介して取得できます。
- MyTestDemoテストクラスを記述し、リフレクションを使用してTestJunitユニットテストクラスのClassオブジェクトを取得し、ユニットテストクラスのすべてのメソッドオブジェクトを取得し、すべてのメソッドオブジェクトをトラバースします。@ MyTestで注釈が付けられたメソッドが追加されて実行される限り、注釈は付けられません。処理操作を行う
- テストクラスを開始し、結果を表示します(実行結果、最後に!)
注意:
- カスタム注釈クラスでは、注釈本体は書き込まれません。つまり、デフォルト値は指定されません。注釈は識別としてのみ機能するため、識別方法をアクティブ化する必要があります
- 注釈クラスもコンパイル後の.classファイルです
- リフレクションメカニズムを介してカスタムアノテーション操作を完了するには、アノテーションおよびリフレクションと同じライフサイクルを与える必要があります
- Junit4とJunit5のプラグイン機能を完了できず、注釈付きメソッドを選択的に実行できること、および認識されないプラグインIDEAを作成できることを知っておく必要があります。実行メソッドの起動項目は生成されません
MyTestアノテーションクラス
package com.mylifes1110.java.anno;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* 此自定义注解@MyTest只是作为需要单元测试的标记,不需要做默认值
* @Retention注解表示给与@MyTest注解生命周期
* 当前定义的注解可以保留到运行时,通过反射机制可以获取注解信息
* 否则反射将对注解没有任何作用,失去了该意义和自定义单元测试的初衷
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
// String value() default "";
}
TestJunitユニットテストクラス
package com.mylifes1110.java.test.junit;
import com.mylifes1110.java.anno.MyTest;
import org.junit.Test;
public class TestJunit {
@Test
public void test1() {
System.out.println("---test1---");
}
@MyTest
public void test2() {
System.out.println("---test2---");
}
@MyTest
public void test3() {
System.out.println("---test3---");
}
public void test4() {
System.out.println("---test4---");
}
}
MyTestDemoテストクラス(主に関数とテストを実現します)
package com.mylifes1110.java.test.junit;
import com.mylifes1110.java.anno.MyTest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 让自定义的MyTest注解起作用
* 通过反射,扫描TestJunit类中有哪些方法上方加了MyTest注解
* 如果加@MyTest注解的则执行它
* 如果没有加@MyTest注解的则不做任何处理
*/
public class MyTestDemo {
public static void main(String[] args) {
/**
* 1.获取TestJunit类对应的Class对象
*/
Class<TestJunit> junitClass = TestJunit.class;
/**
* 获取TestJunit类中所有的方法对象
*/
Method[] methods = junitClass.getMethods();
/**
* 遍历所有方法对象查找有与没有@MyTest注解,并做出响应处理
*/
for (Method method : methods) {
boolean present = method.isAnnotationPresent(MyTest.class);
/**
* TestJunit类中有@MyTest注解的执行该方法
*/
if (present) {
try {
method.invoke(junitClass.newInstance());
} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
} else {
/**
* TestJunit类中没有@MyTest注解的不做任何操作
* 此else分支冗余,只是为了做标记,让你们好理解
*/
}
}
}
}
実行結果グラフ