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物資列表());
某人.攜帶(背包);
成功離開 = 空間.從出口離開(某人);
日記.紀錄(某人.經歷());
}
}
```

## Integration Testing
- Prepare data
- Act
- Assert
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

## 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 輔助解決一些事情