聲明預期定義 require, assert, check, elvis
對參數或狀態,應儘早聲明預期結果 儘管這些聲明,無法讓我們不必寫文件,但他仍讓開發者享有幾個好處
- 對不看文件、註解的協同開發者,預期結果仍會被看見
- 如果不符合預期,對丟出 exception 而不是有預期之外的行為
- 儘早聲明預期,確保在修改任何內容前就 throw exception ,以免一些操作執行、一些未執行,導致不一致的情況
- 程式碼在某種程度上會自我檢查,可不那麼依賴於測試來保證邏輯正確性
儘管放在function body 前段,讓其他開發者更容易看到,但並非每個開發者都會讀 source code ,所以還是得把 require, check 寫在註解裡
- make them more visible
- protect your application stability
- protect your code correctness
- smart cast variable
require
當函式傳入參數時,通常會有在某些條件下參數才能執行的情況
針對傳入參數,呼叫 require
fun demoRequire(int:Int) {
require(int > 0){
"int is smaller than 0"
}
}
throw IllegalArgumentException
check
確保某些狀態,用於 class 內狀態變數,通常擺在 require後
class DemoAssert(){
private var isOpen = false
fun demoCheck(){
check(isOpen){
"is not open for now"
}
}
}
throw IllegalStateException
assert
我們會知道function執行後應該要達到某些條件,但人總有可能犯錯,常見會出錯的情境是
- refactor
- other developer change code or implement
- we made a mistake
class DemoTest{
@Test
fun `run. a sample test`(){
...
assertEquals(10, runResult)
}
}
我們也可以透過 jvm 設置加入 -ea
,將一般 function 寫成
fun pop(num:Int):List<T>{
...
assert(ret.size == num)
return ret
}
這個寫法不會在 production 時執行,僅會在 run test 的時候執行,因為我們通常不希望用戶遇到錯誤,而如果情境是需要用戶知道出錯的時候,應該要用 check
將 assert 至於一般函式,而不限於測試函式的優點
- self check -> 有效率的測試
- 預期的結果會在真實的使用案例下測試,而非固定的 test case
- 可在真實執行的情境下,測試某個部分
- 程式會儘早出錯,離出錯的地方更近,更容易修正
儘管有以上優點,單元測試仍不可被取代
elvis operator
null check with throw or return
fun getString(str:String?){
val input = str ?: return
}
fun getString(str:String?){
val input = str ?: throw("invalidate input")
}
fun getString(str:String?){
val input = str ?: run {
log("invalidate input")
return
}
}