使用 Django 进行测试驱动开发

目录
  • 创建项目
  • 配置 app
  • 编写测试用例
  • 编写代码
  • 执行测试
  • 最后的话

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

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

通常情况下,我们都是先写代码,然后编写测试用例,因此测试驱动开发是反直觉的,那为什么还要这么做呢?基于以下几点原因:

  1. TDD 可以被认为是根据测试用例来说明需求。此后编写源代码,重点是满足这些要求。当测试最终通过时,你可以确信已满足要求。这种专注可以帮助开发人员避免范围蔓延。
  2. TDD 可以通过较短的开发周期提高开发效率。一次解决测试用例中的个别需求可以最大限度地减少干扰因素。重大更改将更容易跟踪和解决,减少了调试工作,提高了效率,并且将更多时间花在开发上。
  3. 编写测试时考虑到了需求。正因为如此,它们更有可能被写成明确的,可以理解的。这样的测试可以作为代码库的优质文档。
  4. 先编写测试用例可确保您的源代码始终具有可测试性,它还保证随着代码库的增长,测试覆盖率始终保持在合理的百分比。

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

  • 当需求不明确时,有时续期会随着开发的进行而逐渐明确,在这种情况下最初编写的任何测试可能会过时。
  • 开发的目的是为了证明某一概念时——例如在黑客马拉松期间,测试通常不是优先事项。

了解了测试驱动开发之后,我们用 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/ 即可看到界面:

最后的话

本文分享了什么是测试驱动开发,并用测试驱动开发的方式 创建了一个简单的 Django 应用程序,用于长度转换。和一般开发的区别就是先写好测试用例,编码是为了让测试用例通过,这样的方式可以使得需求更明确,开发周期更短,增量可控,提高开发效率,保证测试覆盖率。

到此这篇关于使用 Django 进行测试驱动开发的文章就介绍到这了,更多相关Django测试驱动开发内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详尽讲述用Python的Django框架测试驱动开发的教程

    测试驱动开发(TDD)是一个迭代的开发周期,强调编写实际代码之前编写自动化测试. 这个过程很简单: 先编写测试. 查看测试失败的地方 编写足够的代码以使测试通过. 再次测试. 代码重构 . 重复以上操作. 为什么要用TDD? 使用TDD,你将学会把你的代码拆分成符合逻辑的,简单易懂的片段,这有助于确保代码的正确性. 这一点非常重要,因为做到下面这些事情是非常困难的: 在我们的脑中一次性处理所有复杂的问题. 了解何时从哪里开始着手解决问题. 在代码库的复杂度不断增长的同时不引入错误和bug:并且

  • 使用 Django 进行测试驱动开发

    目录 创建项目 配置 app 编写测试用例 编写代码 执行测试 最后的话 所谓测试驱动开发(TDD),就是先编写测试用例,然后编写代码来满足测试用例,具体包含以下步骤: 编写测试用例. 编写代码满足测试用例中的需求. 运行测试用例. 如果通过,说明代码满足了测试用例所定义的需求. 如果未通过,则需要重构代码,直到通过. 重复以上步骤,直到通过全部的测试用例. 通常情况下,我们都是先写代码,然后编写测试用例,因此测试驱动开发是反直觉的,那为什么还要这么做呢?基于以下几点原因: TDD 可以被认为是

  • 浅谈测试驱动开发TDD之争

    前言 在历史上有很多精彩绝伦的神仙打架,比如数学界的牛顿和莱布尼茨关于微积分的旷世之争:比如量子物理中的爱因斯坦和波尔的紫禁之巅:比如足球里的梅西和C罗的旗鼓相当难分高下:又比如滴滴和快滴之间触目惊心的烧钱大战--而在软件行业中,也同样有神仙打架的名场面,那就不得不提的是2014年的那场--测试驱动开发(TDD)之争. 比赛的红方是David Heinemeier Hansson,蓝方是Kent Beck.David Heinemeier Hansson 由于名字较长简写成DHH,Ruby on

  • 用Python进行行为驱动开发的入门教程

    为驱动开发(Behavior-Driven Development,BDD)是一种卓越的开发模式.能帮助开发者养成日清日结的好习惯,从而避免甚至杜绝"最后一分钟"的情况出现,因此对提高代码质量是大有裨益的.其与Gherkin语法相结合的测试结构及设计形式,使得对团队的全部成员包括非技术人员都具有极好的易读性. 所有代码都必须进行测试,这意味着上线时把系统瑕疵降到最低甚至为零.这需要与完整的测试套件相配,从整体把控软件行为,使得检测与维护都能有序进行.这就是BDD的魅力所在,难道不心动吗

  • Nodejs学习笔记之测试驱动

    分享第二章,关于测试驱动.这里的测试主要针对Web后端的测试 -- 你为什么要写测试用例(即测试用例的完善是否是浪费时间),如何完善你的测试用例,代码设计如何简化测试用例的书写,以及一些后期的构想. 1. 你为什么要写测试用例 这个习惯通常会被认为是一种耽误开发进度的行为,你需要花费几乎和开发代码相同的时间来逐步完善你的测试用例.但是在开发过程中,在开发完成一段代码后如果负责任而不是说完全把问题交给测试人员去发现的话,这个时候通常都会去做一些手动的测试.例如: 在代码中执行某些方法,查看输出的值

  • 在Django下测试与调试REST API的方法详解

    对于大多数研发人员来说,都期望能找到一个良好的测试/调试方法,来提高工作效率和快速解决问题.所谓调试,偏重于对某个bug的查找.定位.修复:所谓测试,是检验某个功能是否达到预期效果.测试发现问题后进行调试,从而解决问题. 对于后台研发来说,往往没有客户端研发(Windows/Android等等)那样简单有效的DEBUG方法,比如Step by Step.虽然目前有很多IDE可以实现本地调试,但是因为后台研发的环境复杂,你很难在一台机器上模拟所有的环境,比如线上的数据库只能在内网访问等等,所以很多

  • 详解Spring注解驱动开发之属性赋值

    一.@Value注解 在Person的属性上使用@Value注解指定注入值 public class Person { @Value("#{20-2}") //SpEL表达式 #{} private Integer id; @Value("张三") //基本数据类型 private String name; } 配置类 @Configuration public class MainConfigOfPropertyValues { @Bean public Pers

  • Python中DJANGO简单测试实例

    本文实例讲述了Python中DJANGO简单测试的用法.分享给大家供大家参考.具体如下: 这里以facebook台湾的测试版为例. 仅仅测试用户登录,主要说明测试的使用和django环境的设置. 代码如下: import os import sys import unittest import hashlib TEST_MEMBER_ID = 11 SNS_ID = 100002309745702 TEST_SESSION_KEY = '125737724171219|2.AQCp7ctCYXJ

  • 测试平台开发vue组件化重构前端代码

    目录 基于 springboot+vue 的测试平台开发 一.为什么重构 二.如何拆分 1. 补充对应知识 2. 合理拆分 三.关于项目 基于 springboot+vue 的测试平台开发 继续更新(人在魔都 T_T). 这期其实并不是一个详细的开发过程记录,主要还是针对本次前端重构来聊聊几个关注点. 目前重构的总进度在80%,重构完的页面没什么变化,再回顾一下. 一.为什么重构 目前项目的功能开发重点还是在接口管理这一大块,内容多,任务重,可当我着手准备继续开发新功能的时候发现了个重大的问题.

  • springboot vue测试平台开发调通前后端环境实现登录

    目录 基于 springboot+vue的测试平台开发 一.前端环境搭建 快速安装 二.后端环境搭建 创建应用 配置 application.properties 三.实现登录 1. mysql 建表 2. 后端-实现 /login 接口 3. 前端-修改代码实现登录 4. 解决跨域 5. 后端-实现 /useInfo 接口 6. 后端-实现 /logout 接口 四.小结 基于 springboot+vue的测试平台开发 一.前端环境搭建 在前端框架vue-element-admin这个项目中

  • C语言驱动开发之通过ReadFile与内核层通信

    驱动与应用程序的通信是非常有必要的,内核中执行代码后需要将其动态显示给应用层,但驱动程序与应用层毕竟不在一个地址空间内,为了实现内核与应用层数据交互则必须有通信的方法,微软为我们提供了三种通信方式,如下先来介绍通过ReadFile系列函数实现的通信模式. 长话短说,不说没用的概念,首先系统中支持的通信模式可以总结为三种. 缓冲区方式读写(DO_BUFFERED_IO) 直接方式读写(DO_DIRECT_IO) 其他方式读写 而通过ReadFile,WriteFile系列函数实现的通信机制则属于缓

随机推荐