本文首發於自己博客,歡迎來訪問 & 留言:

使用 GitLab Runner 完成 Django CI?

nova.moe
圖標

Code without tests is broken by design.」 - Jacob.

寫應用,部署應用,很重要的一個環節便是測試(然後就是所謂的 CI/CD( Continuous Integration and Continuous Delivery)),可能許多初學者寫軟體/或者 Web App 會經歷幾個階段(我也是這麼過來的):

  • 直接 xxx startproject yyy 然後開始寫,每天存檔
  • 學會使用 GitHub 之後開始每天晚上將自己寫的代碼推送到 GitHub 作為一個備份
  • 學會在操作失誤之後使用 git reset HEAD --hard 回滾到上一個可用的狀態
  • 和一些同學在 GitHub 上協作,然後多個人修改了同一個文件之後遇到 Conflict ,開始扯皮(我不是說了你不要改這個奇怪的地方嘛?你等會,我先把這個推送了來)
  • 學會使用 Branches 減少扯皮次數,並且服務端腳本通過定期pull GitHub 上的代碼來完成功能的上線(涉及到資料庫修改的就先 down 一下)
  • 發現用戶總是會先比自己發現代碼上的 Bug
  • 開始學習寫一些測試

那麼問題來了:

Django 怎麼寫測試

這個基本可以參考 Django 官方文檔,如果希望自己的代碼看上去有條理一點就不要所有測試全部丟在 tests.py 裡面,可以多創建幾個文件,比如 test_static_views.pytest_auth_functions.py 之類,畢竟:

The default startapp template creates a tests.py file in the new application. This might be fine if you only have a few tests, but as your test suite grows you』ll likely want to restructure it into a tests package so you can split your tests into different submodules such as test_models.py, test_views.py, test_forms.py, etc. Feel free to pick whatever organizational scheme you like.

假設我們需要一個非常簡單的測試,測試一下首頁是否可以工作,可以如何來寫呢?

from django.test import TestCase, Client

# These are tests for static pages and login/register function.
class ViewTests(TestCase):
def test_index(self):
response = self.client.get(/)
self.assertEqual(response.status_code,200)

這樣假設訪問首頁能獲得一個 200 的返回(而不是 403,415 啥的)的話測試就通過啦,本地先驗證一下,使用 python manage.py test <app 的名字> 來測試某一個 app 下的測試,返回結果可能如下所示:

(env) ? app git:(master) python manage.py test <app 的名字>
Creating test database for alias default...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.008s

OK
Destroying test database for alias default...

沒問題了?好的,我們下一步看看如何在 git push 之後讓伺服器幫我們跑一下測試(之後還可以加入一些,測試通過後自動部署的操作)。

GitLab && GitLab Runner

為了(更加貼近 LeetCode 技術棧|希望嘗試一下 Python 的 Web 框架),這裡使用 GitLab 作為項目託管,並且分別演示如何使用 GitLab.com 官方的 Shared Runner (基於 GCE)和使用自己的 Runner (放在自己的 Docker 中)來運行測試(畢竟官方那個… 好像有點慢)。

使用 GitLab Shared Runner

要在 GitLab 上運行自己的測試,我們需要在項目的根目錄下創建一個名為 .gitlab-ci.yml 的文件(當然,也可以不放在根目錄下,不過這樣的話需要自己指定一下),內容可能如下:

stages:
- test

test:
stage: test
script:
- apt-get update -qy
- apt-get install -y python3-dev python3-pip
- cd app # 我的應用放在了 app 目錄下,所以需要先 cd 進去
- cp leetcode-sample/settings.py.example leetcode-sample/settings.py # 我的 settings.py 被 gitignore 了,防止暴露一些敏感信息
- pip3 install -r requirements.txt
- python3 manage.py test

然後直接 push 就可以了,一般來說,你可以看到如下的結果:

看日誌的話最後幾行應該如下:

$ python3 manage.py test
Creating test database for alias default...
.
----------------------------------------------------------------------
Ran 1 test in 0.008s

OK
Destroying test database for alias default...
System check identified no issues (0 silenced).
Job succeeded

和我們想要的一樣,不錯~

使用自己的 GitLab Runner

安裝 Docker 後運行 GitLab Runner,可以參考我的 n0vad3v/dockerfiles 倉庫下的 gitlab-runner ,通過 docker-compose up -d 啟動之後通過 docker ps 獲取到自己的 CONTAINER ID,然後進入容器進行配置:

$ docker exec -it <Container ID> gitlab-runner register

配置方法參考:Registering Runners | GitLab 即可,如果沒有在 .gitlab-ci.yml 中指定的話,會默認使用 ruby:2.7 的包,這裡由於我們主要是 Django 項目,所以可以指定一個 python:3.7 之類的 image,完成之後應該可以在自己的項目設置中看到自己的 Runner:

不過如果你像我這樣隨意打 Tag 的話容易提交了沒法運行,並且報錯:

This job is stuck because the project doesn』t have any runners online assigned to it.

這裡一個簡單粗暴的方法是勾選」Indicates whether this runner can pick jobs without tags」,即可~

多寫測試,盡量測試驅動開發,不僅可以減少上來就寫代碼而導致的後期的麻煩,還可以在一些特殊場合(比如面試的時候)給他人一個比較良好的印象。


推薦閱讀:
相關文章