51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1683|回复: 1
打印 上一主题 下一主题

[讨论] 给 Flask 增加单元测试

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2018-2-27 15:19:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单元测试的重要性不言而喻,比如经典的测试金字塔,最底层的便是单元测试,它越接近代码层,
收益越大。

之前在Flask编写微服务的过程中,并未注意过单元测试,最近准备重构代码的过程中,发现之前
的代码还是有很大的优化空间,而且不适合写单元测试,为了方便单元测试的开展,还需要重新
整理之前的框架,自己感觉非常得不偿失。

虽然是测试出身,但是自己却从来未真正实践单元测试。真的负罪感满满。

最近看了很多单元测试方面的知识,有一句话印象颇深,与大家共勉。

Martin Fowler提到"在你不知道如何测试代码之前,就不该编写程序。而一旦你完成了程序,测试
代码也应该完成。除非测试成功,你不能认为你编写出了可以工作的程序。"

简介

先介绍一下Python的单元测试常用框架

unittest
pytest
nose
unittest

unittest是Python内置的标准类库。它的API跟Java的JUnit、.net的NUnit,C++的CppUnit很相似。

unittest中最核心的四个概念是:test case, test suite, test runner, test fixture。通过继承unittest.
TestCase来创建一个测试用例。

unittest的使用有一些潜规则

每一个测试文件都需要写一个类,对于需要set_up和tear_down的方法,每一个测试文件里面都
需要加上set_up和tear_down
unittest默认是按照字母和数字的顺序运行,倘若需要按照我们指定的顺序执行,需使用 suit.ad
dTest的方式去指定
pytest

pytest是一个功能丰富、灵活的测试框架,但是它的语法很简单。创建一个单元测试就像编写一
个模块一样。相比unittest,实现相同的测试功能,py.test做的事情更少。

pytest有一些特点:

pytest在命令行中有彩色输出
不需要使用特定类模板
setup/teardown 语法与 unittest 的兼容性不如 nose 高,实现方式也不如 nose 直观
nose

nose是对unittest的扩展,使得python的测试更加简单。nose自动发现测试代码并执行,nose
提供了大量的插件,比如测试输出的xUnitcompatible,覆盖报表等等。

nose 不使用特定的格式、不需要一个类容器,甚至不需要 import nose ~(这也就意味着它在
写测试用例时不需要使用额外的 api)。

nose的使用非常简单,自带光环:

不用动不动就写个类,而只是写测试函数;
自动查找和搜集测试,不需要自己手动搭建测试集;
支持插件,可以搭配其他非常实用的标准化插件(coverage, output capture, drop into debugger
on errors, doctests support, profiler)
为测试打标签,并且可以根据标签非常灵活的选择测试集;
并行测试;
更好的支持fixtures;
产生器测试。
粉一下nose的宣言

nose extends unittest to make testing easier.
Flask中加入nose的单测用例

先简单看一下我Flask的服务是

app里面是主框架,main里面分别有api和agent,schedule,agent是封装了邮件发送的异步操作,
schedule是封装了定时执行的后台运行操作,app下面的models是数据库相关的表结构,而和app
同级的tests下面,则是我新增的单测用例文件。

首先新建一个tests的包结构,然后在init.py里面,增加一个类似setup的动作,
  1. from app import create_app, db


  2. app = create_app('testing')
  3. app_ctx = app.app_context()
  4. app_ctx.push()

  5. test_app = app.test_client()
  6. db.drop_all()
  7. db.create_all()


  8. def tearDown():
  9.     app_ctx.pop()
复制代码
在跑单元测试的时候,需要先启动一个testing配置的mock服务,然后先删除数据库,并初始化一个
新的数据库,在测试结束之后,再释放初始化push的app_context。

一般而言,Flask服务需要测试的关注点主要是models,functions,以及views。当然views就是一些
页面的测试,更加类似于用selenium实现。

先简单介绍对一个api和models的测试。
  1. def test_logs_api():
  2.     resp = tests.test_app.get('/api/test')
  3.     assert_equal(resp.status_code, 200)
  4. def test_log():
  5.     log = models.Log(
  6.         date_created=datetime.datetime.now(),
  7.         result=111,
  8.         job_name=111,
  9.     )
  10.     db.session.add(log)
  11.     db.session.commit()

  12.     log_id =models.Log.query.filter(models.Log.result ==
  13.     111).first()
  14.     assert log_id is not None
复制代码
都很简单一目了然,我的经验就是对一个方法或者实例进行测试的时候,只用一个测试。这样方便以
后维护,也使得逻辑更加清晰。

然后在命令行用nose调用执行:

nosetests -v --with-coverage --cover-package=app
然后可以看到测试结果和覆盖率的结果
  1. Name                   Stmts   Miss  Cover
  2. ------------------------------------------
  3. app/__init__.py           44      0   100%
  4. app/config.py             58      3    95%
  5. app/main/__init__.py       3      0   100%
  6. app/main/agent.py         37     16    57%
  7. app/main/api.py          135     53    61%
  8. app/main/schedule.py      37     25    32%
  9. app/models.py             84     13    85%
  10. app/util/__init__.py       0      0   100%
  11. app/util/util.py         130     33    75%
  12. ------------------------------------------
  13. TOTAL                    528    143    73%
  14. ----------------------------------------------------------------------
  15. Ran 6 tests in 6.905s

  16. OK
复制代码
谈谈收获

当真正去写单元测试的时候,才会意识到自己之前只是为了实现业务而工作,虽然基本实现了业务,
但是很多function无法开展单元测试,才真正理解解耦,函数式编程。

我们在编程中应该以测试的思想去影响设计结构,就是我们常说的测试驱动开发,缺乏测试的思想
会给软件项目带来巨大的潜在隐患。

当然测试不是万灵药,软件开发是艰难的工作。为了争取成功,我们必须时刻牢记真正的目标。
不但要解决问题,而且要简洁,高效,优雅的去实现。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-11 02:11 , Processed in 0.067438 second(s), 24 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表