[不做怎么知道系列之Android开发者的30天后端养成故事 Day11] - 测试可以吃吗? #高品质程式 #单元测试

http://img2.58codes.com/2024/20124548js8w2rqAYF.png

哈啰,我们又见面了,今天我们来看看怎么测试一个网站,在开始实作之前,我们必须先釐清一些观念,包含 架站的过程中会遇到什么事情、为什么需要 测试。

架站流程

我简单介绍一下要架站,需要什么流程,其中 需求与设计、开发、测试 与 布署 这四个步骤的流程,会依照你们团队所採用的 开发方法 而有所不同,这是软体工程中的一部分,典型旧型的开发方法是 瀑布模型(Waterfall),以及新型热门的敏捷开发方法有 Scrum、XP 等等,至于怎么挑选适合团队的开发方法,会有团队成员的性格、专案性质等等的变因,再讲下去就扯远了,我们回到流程。

架设开发环境安装程式语言安装框架安装编辑器/IDE需求与设计我的需求在 Day1 已经提完 (虽然是很粗略的版本),但因为我是一个人的开发团队,所以有很多需求细节,都在我脑中,只是没有文件化而已设计则是随着我对 pythondjango 的理解而跟着变动开发就是实际产生网站功能的地方测试测试 功能 是否符合 需求有些公司可能将测试独立出一个 QA 部门 或 测试人员,来负责这部分布署将网站放到一个地方给人使用,而这个地方可能是 公司内部的伺服器,可能是 云端伺服器,也可能是我自己的电脑 等等

前面 Day1~Day10 已经走到开发的阶段,接下来我们来看看测试。

测试,对于开发的重要性 (痛点在哪里?)

在现在的软体产业中,需求变化非常快,有可能今天跟你说我需要部落格,明天就跟你说部落格先不要做了,我现在需要购物车,那么这时候,身为开发人员的你,该怎么维持你的程式码品质 ?

你可能会说「我光是要开发就已经来不及了,我怎么可能还要顾我的品质 ?,都是客户或老闆的错啊,他们不应该这样变来变去,这样怎么可能把事情做好呢 !」,但事实就是这样,山不转路转,你势必需要去习惯这样的文化,所以再回到问题,如何兼顾 开发速度、开发弹性 与 程式码品质 ?

在 TDD 的观念中,品质就是从 测试 来的,当你的测试够明确,你很知道你要达到什么样的效果,就是一个好程式码、一个好功能,但你又会说「我开发就已经不够时间了,怎么还有时间写测试 !」,但问题是,你先写好测试,才有机会省下开发的时间,才能继续写测试,可是没有时间怎么写测试,那你没有写测试怎么有时间,所以才要先写测试才有时间阿 ...

恩 ... 相信你感受到这个矛盾的现象了。总之,我们就是想办法写好测试,开发 就尽量去符合 测试 的目标。

单元测试 (Unit Testing)

单元测试就是「最小单位的测试」,可以小到某个 class 底下的变数型别,也可以到 class 底下的 method 行为,是否符合预期。

shop/models.py

这是我们在 Day9 所完成的 model。

from django.db import modelsfrom django.utils import timezoneimport osdef get_image_path(instance, filename):    return os.path.join('uploads', filename)class Product(models.Model):    # basic info    name = models.CharField(max_length=100, blank=False)    price = models.DecimalField(blank=False, max_digits=100, decimal_places=0)    img = models.ImageField(upload_to=get_image_path, default=get_image_path(instance=0, filename='product-1.jpg'))    # discount    on_sale = models.BooleanField(blank=True, null=True)    tag = models.CharField(max_length=20, blank=True, null=True)    percent_off = models.DecimalField(blank=True, null=True, max_digits=30, decimal_places=1)    sale_price = models.DecimalField(blank=True, null=True, max_digits=30, decimal_places=0)    # for analysis    bought_counter = models.DecimalField(default=0, max_digits=30, decimal_places=0)    created_date = models.DateTimeField(default=timezone.now)    published_date = models.DateTimeField(blank=True, null=True)    def publish(self):        self.published_date = timezone.now        self.save()    def __str__(self):        return self.name

shop/tests/test_models.py

我们先测试一下 field type 是不是符合预期,这边只举出四个栏位,省略其他栏位。

from django.test import TestCasefrom django.db.models import DecimalField, CharField, \    ImageField, BooleanField, DateTimeFieldfrom shop.models import Productclass TestProductFieldType(TestCase):    def test_name_field_type(self):        assert_same_type(self, "name", CharField)    def test_price_field_type(self):        assert_same_type(self, "price", DecimalField)    def test_img_field_type(self):        assert_same_type(self, "img", ImageField)    def test_onsale_field_type(self):        assert_same_type(self, "on_sale", BooleanField)...def assert_same_type(self, field_name, field_type):    self.assertTrue(        isinstance(            get_product_field(field_name),            field_type        )    )def get_product_field(field_name):    return Product._meta.get_field(field_name)

现在的专案架构

http://img2.58codes.com/2024/20124548yODbwbSpv8.png

别忘了先把 django 跑起来

$ python manage.py runserver

单元测试跑起来

$ python manage.py test shop.tests.test_models

这边指定只要跑 test_models.py 这个档案里面的测试项目。

单元测试结果

http://img2.58codes.com/2024/201245488RACEAI425.png

因为实际上我把十个栏位都写进测试了,所以出来会有 10 tests。(先忽略我的 branch 名称,因为我是做完整个 CI 流程才回来写文章的)

单元测试结束,接着来到 整合测试 (Integration Testing)

我们在这边先写个简单的整合测试,来测试网站的其中一个页面是否正常。

shop/tests/test_views.py

我们针对 views.py 里面的 shop_view,来测试 shop_view 这个页面的 function namereachabletemplate file namepage title 等等属性。

from django.test import TestCasefrom django.urls import resolvefrom shop.views import shop_viewclass TestShopPageView(TestCase):    def test_resolve_shop(self):        found = resolve('/')        self.assertEqual(found.func.__name__, shop_view.__name__) # 期望 found.func.__name__ 会等于 shop_view    def test_reachable_shop(self):        response = self.client.get('/')        self.assertEqual(response.status_code, 200)# 期望 status_code 会等于 200 (也就是正常)    def test_template_shop(self):        response = self.client.get('/')        self.assertTemplateUsed(response, 'shop/shop.html')# 期望这页面的 template 是 shop/shop.html 这个档案    def test_title_shop(self):        response = self.client.get('/')        self.assertContains(response, 'RS Django Shop')# 期望这页面的标题是 RS Django Shop

整合测试结果

http://img2.58codes.com/2024/20124548JqJb8AloZm.png
(先忽略我的 branch 名称,因为我是做完整个 CI 流程才回来写文章的)

如此一来,将来我在开发的时候,可能不小心按到键盘,更改到了页面标题名称变成 RS Django Sho,我在跑测试的时候就会抓到,不会等到别人来告诉我。也有一种情况是,你去上厕所忘记锁定,然后你家的猫跳上桌键盘踩踩踩 XD。

测试所带来的效益

当你写了 单元测试整合测试 后,加上有 版本控制 的辅助,你可以 更加大胆地开发新功能、更加大胆地重构,因为有这些工具存在,开发者可以 不用那么怕 牵一髮动全身的窘境。

单日心得总结

我必须先澄清,我假日并没有偷懒 QQ,因为我又犯上次犯过的错误,就是把单篇範围又订得太大了,导致一直不知道怎么收尾。

这篇文章我改了超多次,原定的主题是「试玩 CircleCI,体验持续整合」,等我注册完 CircleCI、绑定 Github 专案后,我发现我根本还没写测试,怎么持续整合 QQ,再来把测试写完,在本地端测试成功了,我就在思考一个问题,那... 我该怎么在 CI 上面执行我的网站 !?,执行了网站才能跑测试阿,心想「该死,我把顺序搞反了...」,可是这时候已经过完一整天了,也无法有系统的写成文章。

隔天我花了一整天研究 Docker,试图想要把我的执行环境包在 Docker 里面,然后再放到 CircleCI 里面去执行我的网站,最后才能跑测试,然而 Docker 这东西真的不是我想像的那么简单,就这样,一整天又过了,我还是无法写成文章,所以就到今天了。

一直违反自己的承诺的感觉是真的很差,尤其又是公开宣布的承诺,不知道你们有没有这种感觉,明明想要遵守承诺,可是又不想让文章沦为散落的杂项日记,自己心理也很清楚,不是因为偷懒造成的,也不是刻意要违背承诺,总之,这种感觉不太妙。

所以呢,今天我们体验了 测试 带来的效益,接下来我们试着了解 Docker 能带给我们什么感受吧 !

我是 RS,这是我的 不做怎么知道系列 文章,我们 明天见。


喜欢我的文章吗? 赶快来看看我都发了什么文章吧:我的文章目录欢迎阅读我的上一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day10] - 你/妳SOLID了吗? #什么是SOLID Principles #减少debug时间 #高品质程式欢迎阅读我的下一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day12] - 容器vs.鸭子vs.搬运工 #Docker #什么是容器? #可转移的执行环境

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章