原文連接:http://blog.speedx.com/backend-test-guidehtml
將測試代碼和運行代碼一塊兒寫是一種很是好的習慣。聰明地使用這種方法將會幫助你更加精確地定義代碼的含義,而且代碼的耦合性更低。python
測試的通用規則:git
測試單元應該集中於小部分的功能,而且證實它是對的。github
每一個測試單元應該徹底獨立。web
經過Mock去除依賴shell
儘可能使測試單元快速運行。數據庫
實現鉤子來持續集成json
咱們經過一個簡單的python
程序及unittest
做爲示例來爲你們介紹如何進行測試,這裏推薦你們使用python3
來運行示例。vim
咱們先建立一個將會使用的測試目錄api
mkdir /tmp/TestHookTest cd /tmp/TestHookTest
下圖爲unittest
包中包含的斷言
咱們如今來寫一個經過用戶名得到github信息的一個函數,並對這個函數進行測試
# test.py import unittest import json import requests def fetch_github_profile(username): response = requests.get('https://api.github.com/users/' + username) return response.json() class SaveDataTest(unittest.TestCase): def test_fetch_github_profile(self): username = 'ZhangBohan' data = fetch_github_profile('ZhangBohan') self.assertEqual(data['login'], username)
經過python3 -m unittest test
運行
每一個都可以單獨運行,除了調用的命令,都需在測試套件中。要想實現這個規則,測試單元應該加載最新的數據集,以後再作一些清理。
若是有數據庫依賴,在每次測試前建立測試數據庫,結束後銷燬該數據庫,測試應該有單獨的數據庫,不要在生產和開發環境測試,避免數據變化引發的測試失敗
經過Mock去除依賴
假設咱們如今想把取得的用戶數據保存到本地,並測試是否正確保存
# test.py import unittest import json import requests def fetch_github_profile(username): response = requests.get('https://api.github.com/users/' + username) return response.json() def save_data(data): with open('data.json', 'w') as f: f.write(json.dumps(data)) class SaveDataTest(unittest.TestCase): def test_fetch_github_profile(self): username = 'ZhangBohan' data = fetch_github_profile('ZhangBohan') self.assertEqual(data['login'], username) def test_save_data(self): data = fetch_github_profile('ZhangBohan') save_data(data) with open('data.json') as f: file_data = json.loads(f.read()) self.assertIsNotNone(file_data) self.assertEqual(data['id'], file_data['id'])
在這個測試中咱們的test_save_data
中的data
依賴fetch_github_profile
中的返回數據,現實狀況中會遇到更爲複雜的依賴,爲了一個測試用例,咱們可能須要構建大量的初始化數據。咱們能夠經過mock來解除這個依賴,讓test_save_data
專一於測試保存數據部分
# test.py import unittest import json from unittest.mock import MagicMock import requests def fetch_github_profile(username): response = requests.get('https://api.github.com/users/' + username) return response.json() def save_data(data): with open('data.json', 'w') as f: f.write(json.dumps(data)) FAKE_PROFILE_DATA = { "login": "ZhangBohan", "id": 2317407 } class SaveDataTest(unittest.TestCase): def test_fetch_github_profile(self): username = 'ZhangBohan' data = fetch_github_profile('ZhangBohan') self.assertEqual(data['login'], username) def test_save_data(self): fetch_github_profile = MagicMock(return_value=FAKE_PROFILE_DATA) data = fetch_github_profile('ZhangBohan') save_data(data) with open('data.json') as f: file_data = json.loads(f.read()) self.assertIsNotNone(file_data) self.assertEqual(data['id'], file_data['id'])
若是一個單獨的測試單元須要較長的時間去運行,開發進度將會延遲,測試單元將不能如期常態性運行。有時候,由於測試單元須要複雜的數據結構,而且當它運行時每次都要加載,因此其運行時間較長。把運行吃力的測試單元放在單獨的測試組件中,而且按照須要運行其它測試單元。
經過代碼提交的本地hook或者webhook來持續集成測試你的代碼。
舉個git本地hook的例子(這可假設你瞭解git hook的工做原理)。
> git init > vim .git/hooks/pre-commit
在.git/hooks/pre-commit
文件中寫入
#!/bin/sh cd /tmp/TestHookTest && python3 -m unittest test
執行:
> chmod +x .git/hooks/pre-commit > git add test.py > git commit -m "test hook" . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK [master (root-commit) b390117] test hook 1 file changed, 9 insertions(+) create mode 100644 test.py
在遠程代碼倉庫部署的webhook能更好的測試所有代碼。