python测试开发教程1简介

软件开发更类似于手工艺,而不是工业。本章主要内容如下

  • 软件测试和质量控制
  • 自动测试和测试套件
  • 测试驱动的开发
  • 集成和功能测试
  • 测试金字塔和奖杯

软件测试和质量控制

软件开发过程在很大程度上受到了制造业标准的启发,在早期,测试和质量控制被引入到产品开发周期中。软件公司经常有质量保证团队,专注于建立流程以保证软件的稳健性和跟踪结果。

质量控制过程通常通过测试计划的执行来实现这种信心。它通常是一个检查表,由专门的团队在生产的各个阶段进行检查,以确保软件的行为符合预期。需求和测试计划、测试用例、测试报告等关联,形成一个闭环。

自动测试

测试用例太多,很多时候需要对回归和手工不能实现的部分进行自动化。
自动化本身也是一种开发,需要对测试用例有一定的组织,为此产生了测试套件。

import unittest


class MyTestCase(unittest.TestCase):
    def test_one(self):
        pass

    def notatest(self):
        pass


class MySecondTestCase(unittest.TestCase):
    def test_two(self):
        pass

    def test_two_part2(self):
        pass


if __name__ == '__main__':
    unittest.main()

执行示例:

$ python 01_automatictests.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK
$ python 01_automatictests.py -v
test_two (__main__.MySecondTestCase) ... ok
test_two_part2 (__main__.MySecondTestCase) ... ok
test_one (__main__.MyTestCase) ... ok

----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

还可以分布在多个文件,比如

├──02_tests │
├── tests_div │

├─── __init__.py │ │

└── tests_div.py │ │
└── tests_sum.py 

大多数测试是按照 "安排,行动,断言(Arrange, Act, Assert) "的模式来写的。

测试驱动的开发

测试可以做的不仅仅是验证我们的代码,测试在设计代码本身中是必不可少的。在实现代码之前编写测试,迫使我们对需求进行推理。

import unittest

class AdditionTestCase(unittest.TestCase):
    def test_main(self):
        result = addition(3, 2)
        assert result == 5

    def test_threeargs(self):
        result = addition(3, 2, 1)
        assert result == 6

    def test_noargs(self):
        result = addition()
        assert result == 0


def addition(*args):
    total = 0
    for a in args:
        total += a
    return total


if __name__ == '__main__':
    unittest.main()

集成和功能测试

集成测试是指不同架构组件的测试,比如:

import unittest

class Authentication:
    USERS = [{"username": "user1",
              "password": "pwd1"}]

    def login(self, username, password):
        u = self.fetch_user(username)
        if not u or u["password"] != password:
            return None
        return u

    def fetch_user(self, username):
        for u in self.USERS:
            if u["username"] == username:
                return u
        else:
            return None


class Authorization:
    PERMISSIONS = [{"user": "user1",
                    "permissions": {"create", "edit", "delete"}}]

    def can(self, user, action):
        for u in self.PERMISSIONS:
            if u["user"] == user["username"]:
                return action in u["permissions"]
        else:
            return False


class TestAuthentication(unittest.TestCase):
    def test_login(self):
        auth = Authentication()
        auth.USERS = [{"username": "testuser", "password": "testpass"}]

        resp = auth.login("testuser", "testpass")
        
        assert resp == {"username": "testuser", "password": "testpass"}

    def test_failed_login(self):
        auth = Authentication()

        resp = auth.login("usernotexisting", "")

        assert resp is None

    def test_wrong_password(self):
        auth = Authentication()
        auth.USERS = [{"username": "testuser", "password": "testpass"}]

        resp = auth.login("testuser", "wrongpass")

        assert resp == None

    def test_fetch_user(self):
        auth = Authentication()
        auth.USERS = [{"username": "testuser", "password": "testpass"}]

        user = auth.fetch_user("testuser")

        assert user == {"username": "testuser", "password": "testpass"}

    def test_fetch_user_not_existing(self):
        auth = Authentication()
                              
        resp = auth.fetch_user("usernotexisting")
              
        assert resp is None


class TestAuthorization(unittest.TestCase):
    def test_can(self):
        authz = Authorization()
        authz.PERMISSIONS = [{"user": "testuser", "permissions": {"create"}}]

        resp = authz.can({"username": "testuser"}, "create")

        assert resp is True

    def test_not_found(self):
        authz = Authorization()

        resp = authz.can({"username": "usernotexisting"}, "create")

        assert resp is False

    def test_unathorized(self):
        authz = Authorization()
        authz.PERMISSIONS = [{"user": "testuser", "permissions": {"create"}}]
                      
        resp = authz.can({"username": "testuser"}, "delete")
                      
        assert resp is False


class TestAuthorizeAuthenticatedUser(unittest.TestCase):
    def test_auth(self):
        auth = Authentication()
        authz = Authorization()              
        auth.USERS = [{"username": "testuser", "password": "testpass"}]
        authz.PERMISSIONS = [{"user": "testuser", "permissions": {"create"}}]      

        u = auth.login("testuser", "testpass")
        resp = authz.can(u, "create")

        assert resp is True


if __name__ == '__main__':
    unittest.main()

功能测试倾向于验证我们是否向用户展示了我们真正想要的功能,多为黑盒测试。
端到端(E2E)测试是一种特殊的功能测试,涉及组件的垂直整合。
系统测试与功能测试本身非常相似,但不是测试单一功能,而是通常测试用户在系统中的整个流程。
验收测试是一种功能测试,多由用户进行。
单元和集成测试的目的是测试实现,而功能测试的目的是测试行为。

参考资料

测试分布模型

  • 金字塔
  • 奖杯
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容