使用 GitLab Runner 完成 Django CI

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」,即可~

多写测试,尽量测试驱动开发,不仅可以减少上来就写代码而导致的后期的麻烦,还可以在一些特殊场合(比如面试的时候)给他人一个比较良好的印象。

發表回覆

你的電郵地址並不會被公開。 必要欄位標記為 *