序章
JUnit は、 Java プログラミング言語の単体テストフレームワークおよび回帰テストフレームワークです。
JUnit の特徴:
- オープンソースフレームワーク
- テストメソッドを識別するための注釈を提供する
- 期待される結果をテストするためのアサーションを提供する
- TestRun はテストを実行するために提供されます。
- 高速、エレガント、そしてシンプルに実行
- 自動的に実行して結果を確認し、即時にフィードバックを提供できます
使用
断言
アサーションは JUnit の主要な機能であり、JUnit のすべてのアサーションは Assert クラスに含まれています。
Assert クラスの主なメソッドは次のとおりです。
メソッド名 | メソッドの説明 |
---|---|
アサートイコール | 渡された期待値が実際の値と等しいことをアサートします |
アサートノットイコール | 渡された期待値が実際の値と等しくないことをアサートします |
アサート配列等しい | 渡される期待される配列が実際の配列と等しいことをアサートします |
アサートNULL | 渡されたオブジェクトが null であることをアサートします |
アサートノットヌル | 渡されたオブジェクトが null ではないことをアサートします |
アサート真 | アサート条件が真である |
アサートFalse | アサート条件が false |
アサート同じ | 2 つのオブジェクトが同じオブジェクトを参照していることをアサートします (「==」と同等) |
アサート違う | 2 つのオブジェクトが異なるオブジェクトを参照していることをアサートします (「!=」と同等) |
断言する | 実際の値が指定された条件を満たすかどうかをアサートします |
注: 上記のメソッドはすべて Assert の静的メソッドであり、 によって呼び出されますAssert.xxx
。直接呼び出す必要がある場合は、次のメソッドを追加する必要があります。import static org.junit.Assert.*;
実行の順序
JUnit では、実行順序は@BeforeClass
、、、、、およびアノテーションによって@Before
決まります。@Test
@After
@AfterClass
注釈 | 導入 |
---|---|
@beforeClass() |
注釈付きメソッドは最初に 1 回だけ実行されます。 |
@afterClass() |
アノテーション付きメソッドは最後に一度だけ実行されます。 |
@before() |
注釈付きメソッドは、テスト ケースごとに、テスト ケースが実行される前に実行されます。 |
@after() |
アノテーション付きメソッドは、テスト ケースごとに、テスト ケースの実行後に実行されます。 |
@Test |
before() メソッドと after() メソッドの間で、各テスト ケースが実行されます。実行順序はコードの位置によって決まります |
例は次のとおりです。
@BeforeClass
public static void beforeClass() {
System.out.println("in before class");
}
//execute only once, in the end
@AfterClass
public static void afterClass() {
System.out.println("in after class");
}
//execute for each test, before executing test
@Before
public void before() {
System.out.println("in before");
}
//execute for each test, after executing test
@After
public void after() {
System.out.println("in after");
}
//test case 1
@Test
public void testCase1() {
System.out.println("in test case 1");
}
//test case 2
@Test
public void testCase2() {
System.out.println("in test case 2");
}
結果を図に示します。
テストを書く
これがテストする暗号化プログラムです
public class Encryption {
/**
* 加密程序,算法是将字符串反转,如 abc 会转为为 cba
* @param content
* @return
*/
public static String encryption(String content){
if (content == null)throw new NullPointerException();
if (content.length() < 2)return content;
char[] data = content.toCharArray();
int size = data.length;
for (int i = 0; i < size/2; i++) {
char c = data[i];
data[i] = data[size - i - 1];
data[size - i - 1] = c;
}
return new String(data);
}
}
テストコードは以下の通りです
public class EncryptionTest {
String content = "abc";
@Test
public void encryption() {
assertEquals(Encryption.encryption(content),"cba");
}
}
パラメトリックテスト
上記のテストコードでは、メソッドをテストするたびに対応する値を設定するのは非常に面倒です。Junit 4 では、新しい機能パラメータ化テストが導入されています。パラメーター化されたテストを使用すると、開発者は異なる値を使用して同じテストを何度も実行できます。5 つの手順に従って、パラメーター化されたテストを作成します。
- クラス
@RunWith(Parameterized.class)
に注釈を付けるために使用します。EncryptionTest
@Parameterized.Parameters
テスト データ コレクションとして使用するオブジェクトのコレクション (配列) を返す、注釈付きのパブリック静的メソッドを作成します。- テスト データの行に相当するものを受け入れる EncryptionTest のパブリック コンストラクターを作成します。
- テスト データの各列にインスタンス変数を作成します。
- インスタンス変数をテスト データのソースとして使用してテスト ケースを作成します。
コードは以下のように表示されます。
@RunWith(Parameterized.class)
public class EncryptionTest {
String result;
String content;
public EncryptionTest(String content, String result) {
this.content = content;
this.result = result;
}
@Parameterized.Parameters
public static Collection primeNumbers(){
return Arrays.asList(new Object[][]{
{
"abc","cba"},
{
"1234","4321"},
{
"",""}
});
}
@Test
public void encryption() {
System.out.println("content = "+content+" result = "+result);
assertEquals(Encryption.encryption(content),result);
}
}
テスト結果を図に示します。
例外テスト
を入力するとcontent = null
、例外がスローされます。@Test
では、異常な状態をテストするにはどうすればよいでしょうか。これにはアノテーションパラメータを使用する必要がありますexpected
。パラメータ値が検出される異常です。対応する例外がスローされた場合、テストは成功しますが、そうでない場合、テストは失敗します。
コードは以下のように表示されます。
@Test(expected = NullPointerException.class)
public void encryption() {
System.out.println("content = "+content+" result = "+result);
assertEquals(Encryption.encryption(content),result);
}
タイムテスト
場合によっては、特定のモジュールの効率をテストしたり、実行時間をテストしたりする必要があります。timeout
@Test のパラメーターを使用して、最大実行時間をミリ秒単位で決定できます。
コードは以下のように表示されます。
@Test(timeout = 1000)
public void encryption() {
System.out.println("content = "+content+" result = "+result);
assertEquals(Encryption.encryption(content),result);
}
非同期テスト
原則: 非同期テストの原則は、テスト スレッドをブロックし、非同期スレッドの実行後にテスト スレッドを実行することです。
ここでの使用wait
とnotiftyAll
実現方法、コードは次のとおりです
/**
*要测试的类
*/
public class Simple {
public interface Callback{
void finish(String result);
}
private Callback callback;
public void setCallback(Callback callback) {
this.callback = callback;
}
public void deal(){
new Thread(){
@Override
public void run() {
try {
//模拟耗时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.finish("完成");
}
}.start();
}
}
/**
*测试类
*/
public class SimpleTest {
private Object lock = new Object();
private int flag = 0;
String res = null;
@Test
public void deal(){
Simple simple = new Simple();
simple.setCallback(result -> {
synchronized (lock){
flag = 1;
lock.notifyAll();
}
res = result;
});
simple.deal();
synchronized (lock){
while (flag == 0){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
assertEquals(res,"完成");
}
}
断言する
Android 単体テスト (1)から移行: JUnit フレームワークのassertThat
使用
上記で使用した基本的なアサーションの一部では、障害発生時の出力情報を設定していないと、アサーションが失敗したときに AssertionError がスローされるだけで、どの部分が間違っているのかを知ることができません。そして、assertThat はこれを解決するのに役立ちます。より読みやすくなりました。
assertThat(T actual, Matcher<? super T> matcher);
assertThat(String reason, T actual, Matcher<? super T> matcher);
このうち、reason はアサーションが失敗した場合の出力情報、actual はアサーションの値、matcher はアサーションのマッチャーです。
一般的に使用されるマッチャー照合順序:
マッチャー | 説明する | 例 |
---|---|---|
は | 引数が後で指定される一致式と等しいことをアサートします | assertThat(5, is (5)); |
いいえ | 引数が後で指定される一致する式と等しくないことをアサートしますassertThat(5, not(6)); | |
に等しい | 引数が等しいことをアサートします | アサートザット(30, 等しいTo(30)); |
等しい場合無視する場合 | 大文字と小文字を無視して文字列の等価性をアサートします | assertThat(“Ab”,equalToIgnoringCase(“ab”)); |
文字列を含む | 文字列に文字列が含まれていることをアサートします | assertThat(“abc”, containsString(“bc”)); |
で始まる | 文字列が特定の文字列で始まることをアサートします | assertThat(“abc”,startsWith(“a”)); |
で終わる | 文字列が特定の文字列で終わることをアサートします | assertThat(“abc”、endsWith(“c”)); |
null値 | パラメータの値が null であることをアサートします | assertThat(null, nullValue()); |
notNull値 | パラメータの値が null ではないことをアサートします | assertThat(“abc”, notNullValue()); |
より大きい | 引数が次より大きいことをアサートします | assertThat(4,greaterThan(3)); |
未満 | 引数が以下であることをアサートします | assertThat(4,lessThan(6)); |
以上 | 引数が以上であることをアサートします | assertThat(4,greaterThanOrEqualTo(3)); |
以下または等しい | 引数が以下であることをアサートします | assertThat(4,lessThanOrEqualTo(6)); |
閉じる | 浮動小数点数が特定の範囲内にあることをアサートします | assertThat(4.0, closeTo(2.6, 4.3)); |
すべての | すべての条件が満たされていることをアサートします (&& と同等) | assertThat(4,allOf(greaterThan(3),lessThan(6))); |
のいずれか | 条件が満たされていること、または同等であることをアサートします。 | assertThat(4,anyOf(greaterThan(9), lessThan(6))); |
hasKey | 断言Map集合含有此键 | assertThat(map, hasKey(“key”)); |
hasValue | 断言Map集合含有此值 | assertThat(map, hasValue(value)); |
hasItem | 断言迭代对象含有此元素 | assertThat(list, hasItem(element)); |
下图为使用assertThat测试失败时所显示的具体错误信息。可以看到错误信息很详细!
当然了匹配器也是可以自定义的。这里我自定义一个字符串是否是手机号码的匹配器来演示一下。
只需要继承BaseMatcher抽象类,实现matches与describeTo方法。代码如下:
public class IsMobilePhoneMatcher extends BaseMatcher<String> {
/**
* 进行断言判定,返回true则断言成功,否则断言失败
*/
@Override
public boolean matches(Object item) {
if (item == null) {
return false;
}
Pattern pattern = Pattern.compile("(1|861)(3|5|7|8)\\d{9}$*");
Matcher matcher = pattern.matcher((String) item);
return matcher.find();
}
/**
* 给期待断言成功的对象增加描述
*/
@Override
public void describeTo(Description description) {
description.appendText("预计此字符串是手机号码!");
}
/**
* 给断言失败的对象增加描述
*/
@Override
public void describeMismatch(Object item, Description description) {
description.appendText(item.toString() + "不是手机号码!");
}
}
@Rule用法
转自Android单元测试(一):JUnit框架的使用的@Rule用法
还记得一开始我们在@Before与@After注解的方法中加入”测试开始”的提示信息吗?假如我们一直需要这样的提示,那是不是需要每次在测试类中去实现它。这样就会比较麻烦。这时你就可以使用@Rule来解决这个问题,它甚至比@Before与@After还要强大。
自定义@Rule很简单,就是实现TestRule 接口,实现apply方法。代码如下:
public class MyRule implements TestRule {
@Override
public Statement apply(final Statement base, final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// evaluate前执行方法相当于@Before
String methodName = description.getMethodName(); // 获取测试方法的名字
System.out.println(methodName + "测试开始!");
base.evaluate(); // 运行的测试方法
// evaluate后执行方法相当于@After
System.out.println(methodName + "测试结束!");
}
};
}
}
我们使用一下我们自定义的MyRule,效果如图:
JUnit - 框架扩展
Cactus
Cactus 是一个简单框架用来测试服务器端的 Java 代码(Servlets, EJBs, Tag Libs, Filters)。Cactus 的设计意图是用来减小为服务器端代码写测试样例的成本。它使用 JUnit 并且在此基础上进行扩展。Cactus 实现了 in-container 的策略,意味着可以在容器内部执行测试。
JWebUnit
JWebUnit は、Web アプリケーション用の Java ベースのテスト フレームワークです。HtmlUnit や Selenium などの既存のフレームワークを統合されたシンプルなテスト インターフェイスでラップし、Web アプリケーションの正確性を迅速にテストできるようにします。
JWebUnit は、プログラムの正しさを検証する一連のアサーションを組み込んだ Web アプリケーションを操作するための高レベルの Java API を提供します。これには、リンクの受け渡し、フォームの入力と送信、フォームのコンテンツの検証、および Web アプリケーションのその他の典型的なビジネス機能が含まれます。
XMLユニット
XMLUnit は、単一の JUnit 拡張クラス XMLTestCase と、アサーションを可能にするいくつかのサポート クラスを提供します。
- 2 つの XML ファイルの相違点を比較します (Diff クラスと DetailedDiff クラスを使用)
- XML ファイルの検証 (Validator クラスを使用)
- XSLT を使用して XML ファイルを変換した結果 (Transform クラスを使用)
- XML ドキュメントの XPath 式の評価 (XPathEngine インターフェイスの実装による)
- XML ファイルの DOM トラバーサル後のスタンドアロン ノード (NodeTest クラスを使用)
モックオブジェクト
単体テストでは、ダミー オブジェクトは複雑な実際の (ダミーではない) オブジェクトの動作を模倣できるため、実際のオブジェクトが単体テストに含めることが非現実的または不可能な場合に役立ちます。