如何用GitHub Actions对Docker化的Django应用程序进行自动化测试

350 阅读6分钟

使用GitHub动作对Docker化的Django应用程序进行自动化测试

在这篇文章中,读者将学习如何用[Pytest]测试Django应用程序,对其进行dockerize,并配置GitHub Actions来自动化Django测试。

Pytest是一个Python库,用于运行Python代码的测试。[GitHub Actions]使你可以在你的仓库中自动完成许多重复性的任务。

Docker确保你的应用程序在所有平台上以同样的方式工作。将这些功能添加到你的应用程序中,可以使其更容易进行[持续交付]和协作。

前提条件

读者应该具备以下条件才能跟上本教程的学习。

  1. 对Django有良好的理解。
  2. 使用Git/GitHub。
  3. 安装了[Docker]和[Docker compose]。

构建一个基本的Django应用程序

让我们建立本教程中要使用的项目。我们将为该项目创建一个新的虚拟环境,这在试图获得所有依赖项的列表时将会很方便。

创建虚拟环境后,用终端执行以下命令安装Django。

(env)$ pip install django

运行下面的命令来创建一个新的项目。

(env)$ django-admin startproject <name_of_project>

例如,如果你的应用程序的名字是django_test_githubactions ,在命令中使用这个名字。

(env)$ django-admin startproject django_test_githubactions

cd 进入包含manage.py的目录,执行下面的命令来初始化Django应用程序。

(env)$ python manage.py startapp blog

settings.py 文件中,将blog 应用程序添加到已安装的应用程序列表中。这一步使Django能够识别它是主程序的一个子程序。

INSTALLED_APPS = [
"blog",  #new

]

我们将为这个演示建立一个博客应用程序,所以在*blog/models.py`文件中,粘贴下面的代码片段。

from django.db import models
    
    class Article(models.Model):  
       author_name = models.CharField(max_length=30)  
       title = models.CharField(max_length=20)  
       content = models.CharField(max_length=200)  
       def __str__(self):  
           return self.title

接下来,我们必须编写显示内容的逻辑。要做到这一点,请浏览app/views.py 。 然后,在该文件中添加下面的代码片断。

from django.shortcuts import get_object_or_404, render
from .models import Article
def content_view(request, pk):
   post = get_object_or_404(Article, pk=pk)
   return render(request, "blog/article.html", {'post':post})

接下来,用下面的代码更新你的urls.py 文件,以便在浏览器中访问该路由。


from blog import views 

urlpatterns = [  
    path('<int:pk>', views.content_view, name="content")
]

接下来,在应用程序目录中创建一个templates 文件夹,以存放显示博客内容的模板。

导航到你的应用程序文件夹,创建templates/blog/article.html ,并粘贴下面的代码。

Blog title:  
    {% if post.content %}  
    {{ post.content }}  
    {% endif %}

迁移models ,开始向数据库添加文章。要做到这一点,进入你的终端/命令提示符并运行。

(env)$ python manage.py makemigrations

然后运行。

(env)$ python manage.py migrate

填充数据库

我们需要填充我们的数据库,以了解我们的应用程序是否按预期工作。要填充数据库,请到你的终端,输入下面的指令,进入Django shell。

(env)$ python manage.py shell

然后一个接一个地运行下面的代码;第二行在数据库中添加一条记录并保存。你可以用同样的格式来添加更多的数据。

>>> from blog.models import Article
>>> Article.objects.create(author_name="Ali",title="First app", content="Some detail of the article").save()`

现在运行你的服务器,进入你的localhost(http://127.0.0.1:8000/),然后添加你刚刚添加的文章的id,像这样:http://127.0.0.1:8000/1,你会看到文章内容被显示出来了。

display-blog.png

如何向Django应用程序添加测试

本节将告诉你如何为你的URL和模型添加测试。在测试应用程序之前,执行下面的命令来安装测试库。

(env)$ pip install pytest pytest-django

Pytest-django是一个插件,它的建立是为了让你更容易在Django中使用Pytest。

接下来,在你的项目根部创建一个名字为pytest.ini 的文件。在pytest.ini 文件中,你将把你的项目的settings.py 文件的路径。

pytest.ini 文件中,粘贴下面的代码。

[pytest]
DJANGO_SETTINGS_MODULE = django_test_githubactions.settings

接下来,在应用程序目录中创建一个测试文件夹,你的该应用程序的所有测试文件都将存放在这里。你将在博客应用程序中创建一个新的目录,blog/tests/

首先,我们将测试urls.py 文件,所以你将在测试文件夹中创建一个新文件blog/tests/test_urls.py

所有测试文件必须以test_ 开始,因为这是Pytest使用的惯例。

将下面的代码粘贴到你刚刚创建的test_urls.py 文件中。

from django.urls import reverse, resolve
from django.urls import path

    class TestUrls: 
    # here, you are checking if the path's view name is content
        def test_post_content_url(self):  
            path = reverse('content', kwargs={'pk':1})  
            assert resolve(path).view_name == "content"  # here you are checking if the path's view name is content 

接下来,我们将对模型进行测试,为其创建一个新文件app/tests/test_models.py ,并添加下面的代码片段。

import pytest  
    from app.models import Article  
    @pytest.mark.django_db  
    def test_article_create():
    # Create dummy data  
       article = Article.objects.create(  
       author_name="Muhammed Ali",  
       title="Simple article",  
       content="This is my content",  
       )  
    # Assert the dummy data saved as expected
       assert article.author_name=="Muhammed Ali"  
       assert article.title=="Simple article"  
       assert article.content=="This is my content"

要运行测试,进入你的命令行并运行。

(env)$ python -m pytest

你应该看到一个类似下图的过程,以显示所有的测试都通过了。

run-test.png

设置Docker

本节帮助你学习如何使用Docker和Docker compose来运行你的应用程序。假设你已经在本地机器上安装了Docker和Docker compose,在你的项目根部创建一个Dockerfile 文件。在Dockerfile ,你将把用于构建Docker镜像的步骤说明。

你刚刚创建的Dockerfile 应该包含下面的代码。

FROM python:3.7-alpine

ENV PYTHONUNBUFFERED 1

COPY ./requirements.txt /requirements.txt
RUN pip install -r /requirements.txt

# make a directory in our Docker image in which we can use to store our source code
# Copy the project folder from our local machine to the docker image
RUN mkdir /project
WORKDIR /project

COPY . .

FROM python:3.7-alpine 是你将继承你的Dockerfile的镜像。它通常是你正在使用的语言。

ENV PYTHONUNBUFFERED 1 是必要的,这样Docker就不会对输出进行缓冲,而且你可以实时看到你的应用程序的输出(例如Django日志)。

COPY ./requirements.txt /requirements.txtrequirements.txt文件复制到你本地机器中的Dockerfile文件旁边,作为我们的Docker镜像*requirements.*txt。

RUN pip install -r /requirements.txt 将requirements.txt文件安装在docker镜像中。

接下来,在你项目的根部创建一个requirements.txt 文件。这个文件将包含一个我们想为项目安装的所有依赖项的列表。

将下面的文字粘贴到requirements.txt 文件中。

asgiref==3.4.1
attrs==21.2.0
Django==3.2.7
pytest==6.2.5
pytest-django==4.4.0
python-dateutil==2.8.2
pytz==2021.1
six==1.16.0
sqlparse==0.4.1

设置Docker Compose

在这一节中,你将编写指令,告诉Docker如何运行你的应用程序。首先,在你项目的根部,创建一个docker-compose.yml 文件,并添加代码行。

version: "3"   # Verion of docker-compose we want to use
services:
  proj:
    build:
    # command that is used to run services
      context: . # builds the current directory
    # map port on local machine to port on the docker image
    ports:
      - "8000:8000"
      
    volumes:
      - .:/project # Updates the image with new changes in the code
    command: >
            sh -c "python manage.py runserver 0.0.0.0:8000"

之后,到你的终端,运行$ docker-compose build ,使用docker-compose配置构建我们的镜像。

Docker-compose运行在0.0.0.0:8000 ,而Django并不认识它,所以你需要在你的settings.py 文件中把它添加到你的ALLOWED_HOSTS ,像这样。

`ALLOWED_HOSTS = ['0.0.0.0']`

现在运行$ docker-compose up ,启动服务器,在浏览器上进入http://0.0.0.0:8000/1,你就会看到你创建的博客。

docker.png

设置GitHub动作

GitHub Actions可以让你在 GitHub 仓库中实现自动化、自定义指定的开发和部署流程。

术语

  1. 工作:行动的分步说明。
  2. 工作流:工作流是一个YAML文件上配置的一个或多个工作的自动化流程的列表。

在你的项目中激活 GitHub 操作

在你的文本编辑器上,导航到你的项目根目录,并在其中创建一个名为.github/workflows 的目录,创建一个名为main.yml f 的文件。main.yml 文件将包含所有的 GitHub Actions 命令。

将下面的代码粘贴到你刚刚创建的main.yml 文件中。

name: test_project  
on:
  # activates the workflow when there is a push or pull request on the main branch
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
jobs:  
  test_project: 
# the operating system your job will run on
     runs-on: ubuntu-latest  
     steps:  
       - uses: actions/checkout@v2  
       - uses: actions/setup-python@v2  
       - run: pip install -r requirements.txt  # install requirements to enable GitHub run our code
       - run: pytest . # run the unit test

上面的代码只是在你的最新推送上运行测试。

工作中的 GitHub 行动

提交并推送你目前拥有的所有代码到 GitHub。推送完代码后,去GitHub上的项目,点击 "Actions "标签。如果你的步骤正确,你应该看到你的GitHub Actions已经完全运行,而且你的应用程序已经被测试,所有测试都通过了。

github-actions.png

当你点击它时,你应该看到这个。

github-actions1.png

为了检查GitHub Actions的意图是否得到满足,你将更新测试,所以它失败了。

在模型的测试中,把它改成。

def test_article_create():  
   article = Article.objects.create(  
   author_name="Muhammed Ali",  
   title="Simple article",  
   content="The article's content",  
   )  
   assert article.author_name=="Muhammed Al" # this will make sure the test fails  
   assert article.title=="Simple article"  
   assert article.content=="The article's content"

提交并推送你的代码。然后,转到你的项目Actions,你应该看到测试失败了,说明我们的GitHub Actions说明是按预期工作的。

fail-test.png

总结

本教程教你为Django应用程序的URL和模型编写单元测试。同时,你可以在你的应用程序被推送到GitHub时自动运行测试的过程。

此外,你还可以在工作流程中添加一些提示性测试,以提高应用程序的持续集成。

希望通过这篇文章,你可以为你未来的项目增加一些用GitHub行动进行持续交付的内容。