用Django进行测试驱动开发第一部分

通过Django进行测试驱动开发 1。

为什么要做呢?

通过使用 Django Girls 教程以及其他一些非常感激的资源,我已经在自学 Django 过程中取得了一些进展。然而,在日语资源中,我还没有找到能够学习 Django 测试驱动开发的内容。我希望这篇文章能为像我这样正在自学编程的人们提供一点参考,因此我写下了这篇帖子。

这篇记录是为了理解如何在Django中进行测试驱动开发(TDD)。由于我还有很多学习不足之处,如果有任何错误之处,请您指正。

我们将根据《Python测试驱动开发指南:使用Django,Selenium和JavaScript》(英文版第二版)来进行学习。

这份参考文献中我们使用Django1.1版本和FireFox进行了功能测试等操作,但是这次我们将使用Django3版本和Google Chrome进行功能测试。此外,我们进行了一些个人改动(比如将项目名改为Config等),但并没有进行大的修改。

那么,我们就开始吧。

建立虚拟环境

# projectディレクトリの作成
$ mkdir django-TDD
$ cd djagno-TDD

# 仮想環境の作成
$ python -m venv venv-tdd

# 仮想環境の有効化
$ venv-tdd/Script/activate

# pipとsetuptoolsのアップグレード
$ python -m pip install --upgrade pip setuptools

# DjangoとSeleniumのインストール
$ pip install django selenium
    installing collected packages: sqlparse, pytz, asgiref, django, urllib3, selenium
    Successfully installed asgiref-3.2.3 django-3.0.2 pytz-2019.3 selenium-3.141.0 sqlparse-0.3.0 urllib3-1.25.7

使用谷歌浏览器进行功能测试,需先下载谷歌浏览器的网络驱动。

因为当前环境是Google Chrome版本:79.0.3945.130(官方版)(64位),所以下载了ChromeDriver 79.0.3945.16。

第一部分:TDD和Django的基础

第一章:使用功能测试设置Django

当决定创建一个网站时,通常的第一步是安装并配置web框架,然后进行编写和修改,但是在TDD中,首先要编写测试。

通过严格遵循下列步骤,实施TDD的开发周期。

    • テストを書く

 

    • テストを実行して失敗することを確認する。

 

    テストが成功するようにコードを書く。

我们首先想要确认的是…

確認事項

Djangoがインストールされていて、問題なく働くこと。

確認方法

ローカルでDjangoの開発用サーバーが確認できること。

为了实施这个操作,使用Selenium来自动控制浏览器。

撰写功能测试

创建 functional_tests.py。

# django-tdd/functional_tests.py

from selenium import webdriver

browser = webdriver.Chrome()
browser.get('http://localhost:8000')

assert 'Django' in browser.title

这是第一次的功能测试。执行它。

$ python functional_tests.py

    Traceback (most recent call last):
    File "functional_tests.py", line 8, in <module>
        assert 'Django' in browser.title
    AssertionError

浏览器将由Selenium自动启动,但看到了错误页面。在Shell上也看到了AssertionError。我想解决这个问题。

启动Django

为了通过这个功能测试,启动Django项目并启动开发服务器。

$ django-admin startproject config .

$ python manage.py runserver

    Watching for file changes with StatReloader
    Performing system checks...

    System check identified no issues (0 silenced).

    You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
    Run 'python manage.py migrate' to apply them.
    January 19, 2020 - 15:36:31
    Django version 3.0.2, using settings 'config.settings'
    Starting development server at http://127.0.0.1:8000/
    Quit the server with CTRL-BREAK.

根据config.settings,可以确定Django(3.0.2)已经启动了开发服务器http://127.0.0.1:8000/。

在这里启动另一个shell并激活虚拟环境,然后执行功能测试。

$ python manage.py functional_tests.py

    DevTools listening on ws://127.0.0.1:54716/devtools/browser/6ddf9ee8-7b35-41f5-8700-d740ef24c8dc

因此,没有显示AssertionError,浏览器也没有显示任何错误。

执行功能测试,确认Django确实正常工作!!!!

将该代码库注册到Git存储库中。

TDD可以与版本控制系统一起进行。

$ git init .

$ type nul > .gitignore

使用.gitignore文件来管理不想使用Git进行跟踪的文件。

#.gitignore
db.sqlite3
debug.log
/venv-tdd

我创建了.gitignore文件,所以现在可以将更改添加进去。

$ git add .
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   .gitignore
        new file:   .vscode/settings.json
        new file:   README.md
        new file:   README_Part1.md
        new file:   chromedriver.exe
        new file:   config/__init__.py
        new file:   config/__pycache__/__init__.cpython-37.pyc
        new file:   config/__pycache__/settings.cpython-37.pyc
        new file:   config/__pycache__/urls.cpython-37.pyc
        new file:   config/__pycache__/wsgi.cpython-37.pyc
        new file:   config/asgi.py
        new file:   config/settings.py
        new file:   config/urls.py
        new file:   config/wsgi.py
        new file:   functional_tests.py
        new file:   manage.py

我不想在这里加入更改的hoge.pyc或者pycache文件夹等等,它们已经被添加到了更改中。我想要将它们排除在外。

$ git rm -r --cached config/__pycache__ .vscode

编辑 .gitignore 文件

# .gitignore
db.sqlite3
debug.log
/venv-tdd
.vscode
__pycache__
*.pyc
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   .gitignore
        new file:   README.md
        new file:   README_Part1.md
        new file:   chromedriver.exe
        new file:   config/__init__.py
        new file:   config/asgi.py
        new file:   config/settings.py
        new file:   config/urls.py
        new file:   config/wsgi.py
        new file:   functional_tests.py
        new file:   manage.py

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   .gitignore
        modified:   README_Part1.md

git status已经按计划修复完毕。
现在可以提交了。

$ git add .

在这里,在提交之前,我不想让Django的config/settings.py文件中的SECRET_KEY等内容被提交。

$ git rm -r --cached config/settings.py
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   .gitignore
        new file:   README.md
        new file:   README_Part1.md
        new file:   chromedriver.exe
        new file:   config/__init__.py
        new file:   config/asgi.py
        new file:   config/urls.py
        new file:   config/wsgi.py
        new file:   functional_tests.py
        new file:   manage.py

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   README_Part1.md

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        config/settings.py

使用python-dotenv将系统变量整理到.env文件中,以避免提交。

$ pip install python-dotenv

更改config/settings.py文件

# config/settings.py
"""
Django settings for config project.

Generated by 'django-admin startproject' using Django 3.0.2.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os
from dotenv import load_dotenv  # 追加

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_NAME = os.path.basename(BASE_DIR)  # 追加

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# .envの読み込み
load_dotenv(os.path.join(BASE_DIR, '.env'))  # 追加

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('SECRET_KEY')  # 変更

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['*']  # 変更


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'config.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 変更
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'config.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'ja'  # 変更

TIME_ZONE = 'Asia/Tokyo'  # 変更

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

在这种状态下添加更改并提交。

$ type nul > .env

在.env文件中添加SECRET_KEY。

# .env
SECRET_KEY = 'your_secret_key'

将.env文件添加到.gitignore中。

db.sqlite3
debug.log
/venv-tdd
.vscode
__pycache__
*.pyc
.env  # 追加

记录变更。

$ git add .
$ git status
$ git commit -m "first commit!"

第一章 总结

我从编写功能测试开始启动了Django项目。
我会继续按照这个步骤阅读下去。

广告
将在 10 秒后关闭
bannerAds