---
# System prepended metadata

title: Test and Automation
tags: [Code]

---

Test and Automation
===

- [Code Refactoring](#Code-Refactoring)

## Type

- Unit testing
  - Solitary
  - Sociable
- Component Testing
- Integration testing
- System testing
- Interface Testing
- Install Testing
- Recovery Testing

## Unit Testing

### Unit

- unit of code
- unit of behavior

### FIRST

- Fast
- Independent
- Repeatable
- Self-Validating
- Timely

### 3A

- Arrange
- Act
- Assert

### Story

#### 教練 ~ 我想寫測試...

```java=
public class Story {
    public void start() {
        // 某人根據上頭的指示,
        .
        .
        .
        // 準備了一些物資放進背包,
        .
        .
        .
        // 尋找出口並開鎖離開,
        .
        .
        .
        // 將自己的經歷紀錄於日誌上
        .
        .
        .
    }
}
```

#### 整理程式碼

```java=
public class Story {
    public void start() {
        // 某人

        // 詢問上頭指示

        // 根據指示準備物資放進背包

        // 尋找出口
        // 開鎖離開

        // 將自己的經歷紀錄於日誌上
    }
}
```

#### Extract Function

```java=
public class Story {
    public void start() {
        function 上頭指示 詢問上頭() {...}
        
        function 背包 準備物資() {...}

        function boolean 從出口離開() {
            // 尋找出口
            // 開鎖
            // 離開
        }

        function boolean 紀錄於日誌上() {...}

        // 某人

        上頭指示 = 詢問上頭();

        背包 = 準備物資();

        成功離開 = 從出口離開();

        某人的經歷 = ...;
        紀錄於日誌上();
    }
}
```

```java=
public class Story {
    public void start() {
        // 某人

        上頭指示 = 詢問上頭();

        背包 = 準備物資(上頭指示);
        某人.攜帶(背包);

        成功離開 = 從出口離開(某人);

        某人的經歷 = ...;
        紀錄於日誌上(某人的經歷);
    }

    private 上頭指示 詢問上頭() {...}
        
    private 背包 準備物資(上頭指示) {...}

    private boolean 從出口離開(某人) {
        // 尋找出口
        // 開鎖
        // 離開
    }

    private boolean 紀錄於日誌上(某人的經歷) {...}
}
```

#### Extract Class

```java=
public class Story {
    class 上頭聯絡窗口 {
        public 上頭指示 詢問上頭() {...}
    }

    class 物資塔 {
        public 背包 拿取物資(物資列表) {...}
    }

    class 異次元空間 {
        public boolean 從出口離開(人) {
            出口 = this.尋找出口();
            this.開鎖(出口);
            return this.離開(人, 出口);
        }

        private 出口 尋找出口() {...}

        private boolean 開鎖(出口) {...}

        private boolean 離開(人, 出口) {...}
    }

    class 日記本 {
        public boolean 紀錄(某人的經歷) {...}
    }

    private final 上頭聯絡窗口 秘書子;

    private final 物資塔 倉庫;

    private final 異次元空間 空間;
    
    private final 日記本 日記;

    public Story() {
        this.秘書子 = new 上頭聯絡窗口();
        this.倉庫 = new 物資塔();
        this.空間 = new 異次元空間();
        this.日記 = new 日記本();
    }

    public void start() {
        // 某人

        上頭指示 = this.秘書子.詢問上頭();

        背包 = 倉庫.拿取物資(上頭指示.to物資列表());
        某人.攜帶(背包);

        成功離開 = 空間.從出口離開(某人);

        日記.紀錄(某人.經歷());
    }
}
```

```java=
public class 上頭聯絡窗口 {
    public 上頭指示 詢問上頭() {...}
}

public class 物資塔 {
    public 背包 拿取物資(物資列表) {...}
}

public class 異次元空間 {
    public boolean 從出口離開(人) {
        出口 = this.尋找出口();
        this.開鎖(出口);
        return this.離開(人, 出口);
    }

    private 出口 尋找出口() {...}

    private boolean 開鎖(出口) {...}

    private boolean 離開(人) {...}
}

public class 日記本 {
    public boolean 紀錄(某人的經歷) {...}
}

public class Story {
    private final 上頭聯絡窗口 秘書子;

    private final 物資塔 倉庫;

    private final 異次元空間 空間;
    
    private final 日記本 日記;

    public Story(
        上頭聯絡窗口 秘書子,
        物資塔 倉庫,
        異次元空間 空間,
        日記本 日記
    ) {
        this.秘書子 = 秘書子;
        this.倉庫 = 倉庫;
        this.空間 = 空間;
        this.日記 = 日記;
    }

    public void start() {
        // 某人

        上頭指示 = this.秘書子.詢問上頭();

        背包 = 倉庫.拿取物資(上頭指示.to物資列表());
        某人.攜帶(背包);

        成功離開 = 空間.從出口離開(某人);

        日記.紀錄(某人.經歷());
    }
}
```

![image alt](https://user-images.githubusercontent.com/88981/52933895-c0d47600-338f-11e9-9034-11e1ad0c42f1.gif)

## Integration Testing

- Prepare data
- Act
- Assert

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

![image alt](https://yu-jack.github.io/images/unit-test/modify-unit-test.gif)

## Code Refactoring

> Argument from Ignorance
>
> -- from Lander University - Philosophy 103: Introduction to Logic

一些些技巧: [Refactoring Techniques](https://refactoring.guru/refactoring/techniques)

Transaction Management:

- Two Phase Commitment Protocol
- TCC
- SAGA
- OutBox

> If you are actually able to build a well-structured monolith,
> you probably don’t need microservices in the first place.
>
> from [Don’t start with a monolith](https://martinfowler.com/articles/dont-start-monolith.html)
> [name=Stefan Tilkov]

## 簡單暴力 vs 抽象化

### 簡單暴力

```java
class Main {
    void main() {
        var customer = new Customer("Bill");
        var order = Order.create(customer, "Coffee");
        var staff = new Staff(9527);
        var cashier = new Cashier();

        // 結帳
        order.setStaff(staff);
        staff.setCashier(cashier);
        staff.setOrders(order);
        cashier.addOrder(order);

        // 泡咖啡
        var cup = new Cup();
        staff.setCup();
        cup.setFilterCone(new FilterCone());
        cup.setCoffeeGround(new Coffee());
        staff.brew(cup);
        staff.wait();
        staff.setFilterCone(null);

        // 送餐
        staff.setCoffeeTo(customer);
        customer.setCoffee(order);
    }
}

```

### 抽象化

```java
class Main {
    void main() {
        var barista = new Barista(9527);
        var customer = new Customer("Bill");
        var order = customer.placeOrder("Coffee");

        barista.processPayment(order);
        barista.make(order);
        barista.serveOrderTo(order, customer);
    }
}

```

### 有啥差別 ??!

|項目\方法|簡單暴力|抽象化|
| --- | --- | --- |
| 資料操作 | Must | Must |
| 主詞 |  | Must |
| 主詞的動作 |  | Must |
| 行為 | Optional | Must |

```java
class 簡單暴力 {
    void main() {
        // 到 DB 拿資料

        // call API

        // 因為資料相依的關係, 有特定行為

        // 塞 DB
    }
}

class 抽象化 {
    void main() {
        // 從 DB 拿資料, 轉換成`主詞`

        // call API

        // 主詞做出某個動作 (ex: 人陷入飢餓狀態)

        // 兩個主詞之間有相依的行為 (ex: 人對門做出打開行為 (人打開門) or 門被人打開)

        // 塞 DB
    }
}

```

#### 神奇小問題

商務邏輯除了 CRUD (不管是單獨的 Service or 別人家的 Service), 還有啥 ?
(ex: 驅動硬體做某事: 發送 SMS, etc...)

諸位認為以下操作在都符合商務邏輯的情況下, 有何不同:

- 一個大 function 解決全世界
- 因為要做的事太多, 所以 call function 輔助解決一些事情
- 因為要做的事太多, 所以掛 side car 進來給 call 輔助解決一些事情
- 因為要做的事太多, 所以 call by HTTP 輔助解決一些事情
- 因為要做的事太多, 所以 call by gRPC 輔助解決一些事情
- 因為要做的事太多, 所以 publish an Event 請 subscriber 輔助解決一些事情
