全网最牛测试开发,使用 Django 进行测试驱动开发实战教程,爆G肝整理

188 篇文章 12 订阅
136 篇文章 28 订阅

一、前言

所谓测试驱动开发(TDD),就是先编写测试用例,然后编写代码来满足测试用例,具体包含以下步骤:

1、编写测试用例。
2、编写代码满足测试用例中的需求。
3、运行测试用例。
4、如果通过,说明代码满足了测试用例所定义的需求。
5、如果未通过,则需要重构代码,直到通过。
6、重复以上步骤,直到通过全部的测试用例。

通常情况下,我们都是先写代码,然后编写测试用例,因此测试驱动开发是反直觉的,那为什么还要这么做呢?基于以下几点原因:
1、TDD 可以被认为是根据测试用例来说明需求。此后编写源代码,重点是满足这些要求。当测试最终通过时,你可以确信已满足要求。这种专注可以帮助开发人员避免范围蔓延。

2、TDD 可以通过较短的开发周期提高开发效率。一次解决测试用例中的个别需求可以最大限度地减少干扰因素。重大更改将更容易跟踪和解决,减少了调试工作,提高了效率,并且将更多时间花在开发上。

3、编写测试时考虑到了需求。正因为如此,它们更有可能被写成明确的,可以理解的。这样的测试可以作为代码库的优质文档。

4、先编写测试用例可确保您的源代码始终具有可测试性,它还保证随着代码库的增长,测试覆盖率始终保持在合理的百分比。

然而,测试驱动开发也不是银弹,以下情形并不适合测试驱动开发:

1、当需求不明确时,有时续期会随着开发的进行而逐渐明确,在这种情况下最初编写的任何测试可能会过时。

2、开发的目的是为了证明某一概念时——例如在黑客马拉松期间,测试通常不是优先事项。

了解了测试驱动开发之后,我们用 Django 来演示一下测试驱动开发的过程。(Python 3.7 以上,Django 2.0 以上)
首先描述需求,我们要实现这样一个单位换算功能的 Web 应用,可以在厘米、米、英里直接互相转换,Web 界面如图所示:

请添加图片描述
请添加图片描述

二、创建项目

首先,我们创建一个名字叫 convert 的项目:

pip install django
django-admin startproject converter

此时 Django 已经为我们生成了 converter 目录及基本的项目文件:

converter/
    converter/
        __init__.py
        settings.py
        urls.py
        wsgi.py
    manage.py

然后,进入 converter 目录,创建一个名字叫 length 的 app:

cd converter
python manage.py startapp length

然后你会看到这样的目录结构:

converter/
    converter/
        __init__.py
        settings.py
        urls.py
        wsgi.py
    length/
        __init__.py
        admin.py
        apps.py
        migrations/
            __init__.py
        models.py
        tests.py
        views.py
    manage.py

三、配置 app

修改 converter/settings.py,在 INSTALLED_APPS 里加入 lengh :

INSTALLED_APPS = [
    .
    .
    .
    'length',
]

然后在 length 目录下新建 urls.py,写入以下内容:

from django.urls import path

from length import views

app_name = 'length'
urlpatterns = [
    path('convert/', views.convert, name='convert'),
]

最后在 converter/urls.py 中指向 length/urls.py:

from django.contrib import admin
from django.urls import path, include
urlpatterns = [
    path('admin/', admin.site.urls),
    path('length/', include('length.urls')),
]

这样一个没有任何业务逻辑的项目就创建成功了,接下来编写测试用例

编写测试用例
在 lengh 目录下新建 tests.py,写入以下内容:

from django.test import TestCase, Client
from django.urls import reverse


class TestLengthConversion(TestCase):
    """
    This class contains tests that convert measurements from one
    unit of measurement to another.
    """

    def setUp(self):
        """
        This method runs before the execution of each test case.
        """
        self.client = Client()
        self.url = reverse("length:convert")

    def test_centimetre_to_metre_conversion(self):
        """
        Tests conversion of centimetre measurements to metre.
        """
        data = {
            "input_unit": "centimetre",
            "output_unit": "metre",
            "input_value": 8096.894
        }
        response = self.client.get(self.url, data)
        self.assertContains(response, 80.96894)

    def test_centimetre_to_mile_conversion(self):
        data = {
            "input_unit": "centimetre",
            "output_unit": "mile",
            "input_value": round(985805791.3527409, 3)
        }
        response = self.client.get(self.url, data)
        self.assertContains(response, 6125.5113)

上述代码有两个测试用例,分别代表两个需求。test_centimetre_to_metre_conversion 代表厘米转米的需求,而 test_centimetre_to_mile_conversion 代表厘米转英里的需求。

四、编写代码

这和 Django 开发没什么两样,先编写一个 forms.py,内容如下:

from django import forms

class LengthConverterForm(forms.Form):
    MEASUREMENTS = (
        ('centimetre', '厘米'),
        ('metre', '米'),
        ('mile', '英里')
    )
    input_unit = forms.ChoiceField(choices=MEASUREMENTS)
    input_value = forms.DecimalField(decimal_places=3)
    output_unit = forms.ChoiceField(choices=MEASUREMENTS)
    output_value = forms.DecimalField(decimal_places=3, required=False)

然后编写 html,在 length 目录下新建 templates/length.html,内容如下:

<html lang="en">
  <head>
    <title>Length Conversion</title>
  </head>
  <body>
    <form action={% url "length:convert" %} method="get">
      <div>
        {{ form.input_unit }}
        {{ form.input_value }}
      </div>
      <input type="submit" value="转换为:"/>
      <div>
        {{ form.output_unit }}
        {{ form.output_value }}
      </div>
   </form>
  </body>
</html>

然后编写最重要的视图函数 views.py,内容如下:

from django.shortcuts import render

from length.forms import LengthConverterForm

convert_to_metre = {
    "centimetre": 0.01,
    "metre": 1.0,
    "mile": 1609.34
}
convert_from_metre = {
    "centimetre": 100,
    "metre": 1.0,
    "mile": 0.000621371
}

# Create your views here.
def convert(request):
    form = LengthConverterForm()
    if request.GET:
        input_unit = request.GET['input_unit']
        input_value = request.GET['input_value']
        output_unit = request.GET['output_unit']
        metres = convert_to_metre[input_unit] * float(input_value)
        print(f"{metres = }, {input_value = }")
        output_value = metres * convert_from_metre[output_unit]
        data = {
            "input_unit": input_unit,
            "input_value": input_value,
            "output_unit": output_unit,
            "output_value": round(output_value,5)
        }
        form = LengthConverterForm(initial=data)
        return render(
            request, "length.html", context={"form": form})
    return render(
        request, "length.html", context={"form": form})

五、执行测试

执行策四并不需要启动 django 的 runserver:
请添加图片描述
出现 OK 说明测试通过,启动 django:

python manage.py runserver

打开浏览器,访问 http://localhost:8000/length/convert/ 即可看到界面:
请添加图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值