2018年4月22日 星期日

@Rule、常用方法、測試其他類別 (JUnit4 二)

※@Rule


※內鍵的 Rule

※所謂內鍵,就是在 org.junit.rules 這包裡

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.Timeout;
    
public class AppTest3 {
    @Rule
    public Timeout timeout1 = Timeout.millis(10);
    // public Timeout timeout2 = new Timeout(10, TimeUnit.MILLISECONDS);
    
    @Rule
    public final ExpectedException thrown = ExpectedException.none();
    
    @Test
    public void xxx() throws InterruptedException {
        Thread.sleep(5);
    }
    
    @Test
    public void ooo() throws InterruptedException {
        Thread.sleep(5);
    }
    
    @Test
    public void zzz() throws InterruptedException {
        thrown.expect(ArithmeticException.class);
        int i = 1 / 0;
    }
}

※這個annotation是 4.7 版增加的,宣告時一定要 public

※@Test 裡的 timeout 和 expected 都有,但宣告 @Rule 是全域的,每個方法都會遵從

※ExpectedException.none() 表示不能有例外


※Verifier

原本的測試結束後,會執行這裡的邏輯,這裡的邏輯過了,測試才會過

@Rule
public Verifier verifier = new Verifier() {
    @Override
    protected void verify() {
        Assert.assertEquals(1, 1);
    }
};

※可看高手寫的文章

※自訂 Rule

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
    
public class RuleTest implements TestRule {
    public Statement apply(Statement base, Description des) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                System.out.println("className=" + des.getClassName());
                System.out.println("displayName=" + des.getDisplayName());
                System.out.println("methodName=" + des.getMethodName());
                System.out.println("children=" + des.getChildren());
                System.out.println("annotations=" + des.getAnnotations());
                base.evaluate();
            }
        };
    }
}

※實作 TestRule 後,覆寫 apply 方法

※測試

@Rule
public RuleTest ruleTest = new RuleTest();
    
@Test
public void xxx() throws InterruptedException {
    Thread.sleep(5);
    System.out.println("aaa\r\n");
}
    
@Test
public void ooo() throws InterruptedException {
    Thread.sleep(5);
    System.out.println("bbb\r\n");
}

※如果不想寫 class 去實作,還可以用匿名和 lambda,如下:
@Rule
public TestRule xxx = new TestRule() {
    @Override
    public Statement apply(Statement base, Description des) {
        System.out.println("className=" + des.getClassName());
        System.out.println("displayName=" + des.getDisplayName());
        System.out.println("methodName=" + des.getMethodName());
        System.out.println("children=" + des.getChildren());
        System.out.println("annotations=" + des.getAnnotations());
//        try {
//            base.evaluate();
//        } catch (Throwable e) {
//            e.printStackTrace();
//        }
        return base;
    }
};
    
    
    
@Rule
public TestRule ooo = (base, des) -> {
    System.out.println("className=" + des.getClassName());
    System.out.println("displayName=" + des.getDisplayName());
    System.out.println("methodName=" + des.getMethodName());
    System.out.println("children=" + des.getChildren());
    System.out.println("annotations=" + des.getAnnotations());
    return base;
};

※此時不用寫 base.evaluate(),否則會執行兩次 @Test 裡的方法



※常用方法

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
    
public class AppTest {
    @Test
    public void testApp() {
        assertEquals(5, 5);
        assertEquals("我錯了", 5, 5);
    
        AppTest t = new AppTest();
        assertSame(t, t);
    
        // Assert.fail();//一定不會過
    
        final Integer FIVE = 5;
        assertThat(FIVE, CoreMatchers.anything());// 一定會過
        assertThat(FIVE, CoreMatchers.is(5));// 5等於5嗎?
        assertThat(FIVE, CoreMatchers.not(10));// 5是10嗎
        assertThat(FIVE, CoreMatchers.notNullValue());// 5不是null嗎
    
        // 全部是5才會過
        assertThat(FIVE, CoreMatchers.allOf(CoreMatchers.is(5), CoreMatchers.is(5), CoreMatchers.is(5)));
    
        // 有一個是5就會過
        assertThat(FIVE, CoreMatchers.anyOf(CoreMatchers.is(1), CoreMatchers.is(5), CoreMatchers.is(2)));
    }
}

※很多 assertXxx 有很多的 overloading 方法,有些第一個參數都是String,可以打一些字,出錯時會顯示裡面的內容



※測試其他類別

@RunWith(Suite.class)
@Suite.SuiteClasses({ 
    TestXxx.class ,TestOoo.class
})
public class TestHaHaHa {
    
}

※可以測試 TestXxx 和 TestOoo 這兩個類別

※經過測試,TestHaHaHa 裡面只能有一個 @Test,但也不會被執行

沒有留言:

張貼留言