無測試,不編碼。有持續運行的單元測試,是保持項目健康最基本的要求。在多人協做的內部項目中,這一點尤爲重要。
基於 OpenResty 的項目開發天然不會例外。html
咱們考察過 OpenResty 本身的測試框架 test-nginx
,發現該框架偏向於對接口進行測試。把它用做單元測試,猶如用園藝剪裁紙。
以 lua 應用的角度看,busted卻是個合適的單元測試框架。只是 OpenResty 項目代碼中不免會用到 OpenResty 的 API。
若是不能在 OpenResty 上下文中運行測試,那麼這些 API 就沒法調用。顯然咱們不可能把這些 API 都分離出去,或者 mock 掉。
這麼作不切實際。nginx
好在 OpenResty 提供了 resty
命令行工具,可以以一次性命令的形式在 OpenResty 上下文運行給定的 lua 代碼。
結合 resty
和 busted
兩個工具,有一個辦法能夠在 OpenResty 上下文中運行 busted 的測試代碼。git
首先,注意要安裝 lua5.1 對應的 luarocks。luarocks 默認的 lua 版本是 5.2, 因此安裝的時候須要配置一下。
若是可以像這樣,直接指定使用安裝 OpenResty 時附帶的 luajit,那就更好了:程序員
./configure --with-lua="/usr/local/openresty/luajit" --lua-suffix="jit" --with-lua-include=/usr/local/openresty/luajit/include/luajit-2.1/
而後 sudo luarocks install busted
, 安裝 busted。github
查看命令行工具 busted 的內容,會發現它實際上是個啓動腳本:框架
#!/usr/bin/env lua -- Busted command-line runner require 'busted.runner'({ standalone = false })
OK,如今就讓 resty 去執行這個腳本吧!函數
假設項目結構以下:工具
.. ├── src │ └── code.lua └── test └── test_spec.lua └── busted_runner.lua
其中 busted_runner.lua
的內容是:單元測試
require 'busted.runner'({ standalone = false })
咱們能夠這樣運行:測試
# 當前工做目錄是 test resty -I ../src busted_runner.lua --verbose test_spec.lua
解釋下,-I
參數後面跟着的是 lua 模塊的路徑,後面跟着的是要執行的代碼文件和用戶參數。因此上面的命令等價於 busted --verbose test_spec.lua
。
使用 resty
來運行 lua 代碼有一個侷限。它會在 ngx.timer
的上下文運行代碼,致使許多跟請求上下文相關的 OpenResty API
依然是沒法調用的。舉個例子,若是待測試代碼裏面調用了 ngx.location.capture
,執行測試會獲得這樣的結果:
Error → test_spec.lua @ 7 topic feature test_spec.lua:15: API disabled in the current context
不過這已足矣,畢竟咱們是在作單元測試而非接口測試。像是請求上下文的東西,就應該在測試時 mock 掉。至於怎麼 mock,這屬於
busted 的範疇,請參考 busted 的文檔。
有了測試,下面的需求就是統計測試的覆蓋。
倘若有具體的測試覆蓋程度,程序員們能夠針對性地編寫測試,對哪些地方缺少測試也心知肚明。
另外,還能夠求出項目的測試覆蓋率。
測試覆蓋率不單單可以衡量項目的健康程度。覆蓋率的增增減減,會激勵程序員們儘量地多寫測試。
誰會願意看着本身新增的代碼一片紅色(無測試覆蓋)?天然而然的,若是每次提交的時候,能夠及時得到測試覆蓋的反饋,便能保持一個較高的覆蓋率。
在 lua 中有一個庫 luacov ,能夠實現這樣的功能。
在測試運行時加入 luacov ,它會在每一行加入鉤子函數,觸發對測試覆蓋的統計。luacov 會把統計到的覆蓋率報告在luacov.stats.out
文件中。
busted已經內置了 luacov 支持,因此咱們要操心的事情就少不少。
須要往前面的 busted 命令添加 --coverage
選項:
resty -I ../src -e 'require "busted.runner"({ standalone = false })' -- --coverage --verbose test_spec.lua
爲了讓 luacov 可以寫出覆蓋報告,還須要在 .luacov
下配置:
tick = true
若是不這麼作,咱們就沒辦法獲取測試覆蓋結果了。由於 luacov 默認只在程序退出時才寫入覆蓋報告,而咱們的 openresty
是做爲後臺程序運行的。設置了 tick = true
後,luacov 會按期更新覆蓋報告。除了 tick
,你還能夠在 .luacov
中設置許多 luacov 相關的配置:
http://keplerproject.github.i...
如今已經有了份 luacov.stats.out
了,它長這樣:
127:/usr/local/share/lua/5.1/busted/init.lua 0 0 0 0 4 8 4 0 4 4 0 0 10 20 10 0 10 10 0 0 36 36 0 72 0 0 0 0 36 0 36 36 36 0 36 0 36 36 72 72 36 0 0 0 0 0 0 72 0 0 36 36 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 92 49:/usr/local/share/lua/5.1/busted/languages/en.lua 1 0 1 0 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 1 23:/usr/local/share/lua/5.1/busted/modules/files/lua.lua 1 0 1 0 0 50 100 50 1 0 0 8 1 0 0 4 4 0 0 4 1 0 1 107:/usr/local/share/lua/5.1/busted/modules/files/moonscript.lua 1 0 2 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 1 ...
顯然,這一份不是人類可讀的版本。
接着運行 luacov YOUR_SRC_DIR
能夠生成出 luacov.report.out
。
這一份就是最終的測試覆蓋率報告:
... ****0 for c, v in pairs(colorvalues) do ****0 colors[c] = makecolor(v) end ****0 return colors ============================================================================== Summary ============================================================================== File Hits Missed Coverage ...
固然這一份也不怎麼「對人類友好」。若是嫌 luacov 默認生成的報告太粗糙,能夠使用第三方的 reporter:
https://github.com/keplerproj...
或者,本身動手,豐衣足食:造一個 reporter 輪子。
這方面沒有什麼文檔,只能去讀luacov 默認的 reporter 實現
另一個思路是,寫個腳本去解析生成的 luacov.report.out
測試報告,去生成更加可視化的版本(或者跟現有的 CI 平臺對接)。