# JUnit

## JUnit

### 前置準備

參考資料:(<https://www.jetbrains.com/help/idea/create-tests.html>)

下載套件:

junit.jar & hamcrest-core.jar(<https://github.com/junit-team/junit4/wiki/Download-and-Install>)

### 第一個測試案例

參考資料:(<http://www.java2s.com/Tutorials/Java/JUnit/0040__JUnit_HelloWorld.htm>)

### 共通事件

參考資料:(<https://ithelp.ithome.com.tw/articles/10192896>)

| name        | static | 說明            |               |
| ----------- | ------ | ------------- | ------------- |
| BeforeClass | O      | 整個開始前執行一次     | 每個case前都會執行一次 |
| After       | X      | 每個case後都會執行一次 |               |
| AfterClass  | O      | 整個測試案例跑完會執行一次 |               |

## 3A原則

在使用@Test註解的方法，即測試案例內編寫：

Arrange：初始化目標物件(待測類別)、初始化相依物件、方法參數、預期結果(excepted)

Act：調用目標物件及欲測試的方法

Assert：驗證實際結果(actual)是否符合預期結果

```
@Test
public void getDirNameTest() {
    // 1. Arrange
    Main m = new Main();
    String src = "./music";
    String excepted = "music";

    // 2. Act
    String actual = m.getDirName(src);

    // 3. Assert
    assertThat(actual).isEqualTo(excepted);}
```

(3A的另外一種描述方式 建造-操作-檢查 BUILD-OPERATE-CHECK)

### Assertj-core 可讀性更好的Assert套件 (jdk8)

參考資料:(<https://ithelp.ithome.com.tw/articles/10193175>)

Github:(<https://github.com/joel-costigliola/assertj-core>)

3.8.0 jar下載點:<http://central.maven.org/maven2/org/assertj/assertj-core/3.8.0/>

2.9.1 jar下載點:<https://jar-download.com/artifacts/org.assertj/assertj-core/2.9.1/source-code>

ERROR Code:

```
java: cannot access java.util.function.Predicate
  class file for java.util.function.Predicate not found
```

經查詢 Predicate 是JDK8新增的項目，根據GitHub內所言

```
Note that AssertJ 3.x requires at least Java 8 and AssertJ 2.x requires at least Java 7.
```

雖然教學文章內是使用 Assertj 3.8.0 ，但我目前只能嘗試JDK7，故接下來皆是改用 2.9.1 的版本。

### 硬斷言和軟斷言

參考文章:(<https://ithelp.ithome.com.tw/articles/10193404>)

軟斷言範例:

```
    @Test
    public void Case4(){
        int actual1 = 5;
        String actual2 = "10";

        SoftAssertions softAssertions = new SoftAssertions();

        softAssertions.assertThat(actual1).isLessThan(4);

        softAssertions.assertThat(actual2).isEqualTo("11");

        softAssertions.assertAll();
    }
```

要記得執行最後一行 `.assertAll()` 才會執行斷言。

#### 注意事項

當我們寫測試的時候，我們必須遵守這樣的原則：

不應在測試方法中加入業務邏輯，不要造成維護上的困難 確保我們的測試易於讀寫

但使用軟斷言： 可能把業務邏輯加入到測試案例中，這會使得讀者的注意力會從測試本質，轉移到實現細節上，也就是說變得難以閱讀。 並且因為業務邏輯加入，當單一狀態的改變時，造成相關的測試也都需要進行變更，這造成維護上的困難。

所以一般情況下是不使用的好...

#### 自訂斷言

參考資料:(<https://ithelp.ithome.com.tw/articles/10193640>)

#### Exception

參考資料:(<https://stackoverflow.com/questions/31423643/try-catch-in-a-junit-test>)

**使用 JUnit 去捕捉，就類似用一個大的 try .. catch 包住這整個Test**

```
@Test(excepted = FileNotFoundException.class)
public void someTest() throws Exception {
    //do something..
}
```

但是上述這個寫法的缺點，在於有可能並不是我們期望的那一行所噴的錯，有可能是其他行噴的，但我們無法察覺。

**使用 AssertJ 編寫斷言**

前置條件：此系統必須是 Java 8

**AssertJ提供了org.assertj.core.api.Assertions.catchThrowable()方法來捕捉異常**

```
@Test
public void example_Exception() {
    Throwable throwable = catchThrowable(()-> throwException());

    assertThat(throwable)
            .isExactlyInstanceOf(Exception.class)
            .hasMessageContaining("Magic");
}

private void throwException() throws Exception {
    throw new Exception("Magic");
}
```
