Testing with asyncio

之前有说过应用开发者不需要将loop当作参数在函数间传递,只需要调用asyncio.get_event_loop()即可获得。但是在写单元测试时,可能会需要用多个loop(每个测试用一个单独的loop),问题来了:是否为了支持单元测试而要将loop作为函数参数传入呢?

先看个例子。

import asyncio
from typing import Callable

async def f(notify: Callable[[str], None]):    # 1
    # < ... some code ... >
    loop = asyncio.get_event_loop()    # 2
    loop.call_soon(notify, 'Alert!')    # 3
    # < ... some code ... >
  1. 想象一个coroutine内部需要通过call_soon调用另一个函数,这个函数可能是logging,发聊天信息,短线股票操作或其它任何操作;

  2. 仍然不通过函数参数来获取loop,但要记住一点,这个方法调用始终获取的是当前线程的loop;

  3. 将回调函数及其参数添加到loop的下一次迭代中。


最佳方式是通过fixture来为异步代码提供loop,Pytest将fixtures中定义的函数返回值作为参数传入测试函数中,描述起来有些复杂,用代码展示一下。

# conftest.py    # 1
import pytest

@pytest.fixture(scope='function')   # 2
def loop():
    loop = asyncio.new_event_loop()    # 3
    try:
        yield loop
    finally:
        loop.close()    # 在结束时关闭loop
  1. Pytest将会自动导入名称为“conftest.py”的文件并使其中的配置生效;

  2. 这里创建了一个fixture,scope参数告诉Pytest这个fixture的作用范围,用function限制将会使得每个函数都获得新的loop;

  3. 创建一个全新的loop,但不会立刻让其开始运行。


上述代码有个错误,不要直接使用它,错误很微妙,但也是本章的全部要点,下面开始讨论它,先给一个测试用例。

from somewhere import f    # 1

def test_f(loop):    # 2
    collection = []    # 3
    def f_notify(msg):    # 4
        collection.append(msg)

    loop.create_task(f(f_notify))   # 5
    loop.call_later(1, loop.stop)   # 6
    loop.run_forever()

    assert collection[0] == 'Alert!'    # 7
  1. 这里当作伪代码,表示f是一个在其它模块中定义的coroutine;

  2. Pytest会识别loop函数名并从fixtures中找到这个函数并传入它的调用返回值;

  3. 用一个容器收集notify的信息;

  4. 这是notify函数;

  5. 安排一个coroutine调用notify作为task;

  6. 因为loop是run_forever的,用call_later确保loop会停止;

  7. 此处进行测试。


上面提到有个错误,在这个导入的coroutine函数f中,loop是通过get_event_loop()获得的,而非fixture中提供的,所以这个测试会失败,因为通过get_event_loop()获得的loop压根不会运行。

一个解决办法就是明确地给函数传入loop作为参数,这样就能保证正确的loop被使用,然而这样写代码十分痛苦,因为这样一来大量的函数都要传入loop参数。

有个更好的办法就是,当一个新的loop运行时,将这个loop设置为当前线程的loop,这样get_event_loop()返回的总是最新的loop,这对单元测试十分有用。

# conftest.py
import pytest

@pytest.fixture(scope='function')
def loop():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)    # 这个方法执行后,所有后续的get_event_loop获得的都是fixture中的loop,不需要显式地将loop作为参数传入了
    try:
        yield loop
    finally:
        loop.close()    

深入Asyncio(十二)Asyncio与单元测试的更多相关文章

  1. springboot(十二):springboot单元测试、打包部署

    单元测试 1.在pom包中添加spring-boot-starter-test包引用 <dependency> <groupId>org.springframework.boo ...

  2. 20155322 2016-2017-2 《Java面向对象程序设计》第十二周课堂练习之Arrays和String单元测试

    20155322 2016-2017-2 <Java面向对象程序设计>第十二周课堂练习之Arrays和String单元测试 练习目地 在IDEA中以TDD的方式对String类和Array ...

  3. Spring Boot干货系列:(十二)Spring Boot使用单元测试(转)

    前言这次来介绍下Spring Boot中对单元测试的整合使用,本篇会通过以下4点来介绍,基本满足日常需求 Service层单元测试 Controller层单元测试 新断言assertThat使用 单元 ...

  4. python 并发专题(十三):asyncio (二) 协程中的多任务

    . 本文目录# 协程中的并发 协程中的嵌套 协程中的状态 gather与wait . 协程中的并发# 协程的并发,和线程一样.举个例子来说,就好像 一个人同时吃三个馒头,咬了第一个馒头一口,就得等这口 ...

  5. Spring Boot(十二):spring boot如何测试打包部署

    Spring Boot(十二):spring boot如何测试打包部署 一.开发阶段 1,单元测试 在开发阶段的时候最重要的是单元测试了,springboot对单元测试的支持已经很完善了. (1)在p ...

  6. 20155207JAVA第十二周课堂练习

    20155207JAVA第十二周课堂练习 教材代码检查--P98 修改教材P98 Score2.java, 让执行结果数组填充是自己的学号 Arrays和String单元测试 在IDEA中以TDD的方 ...

  7. 前端开发中SEO的十二条总结

    一. 合理使用title, description, keywords二. 合理使用h1 - h6, h1标签的权重很高, 注意使用频率三. 列表代码使用ul, 重要文字使用strong标签四. 图片 ...

  8. CRL快速开发框架系列教程十二(MongoDB支持)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. 我的MYSQL学习心得(十二) 触发器

    我的MYSQL学习心得(十二) 触发器 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数 ...

  10. Web 前端开发精华文章推荐(jQuery、HTML5、CSS3)【系列十二】

    2012年12月12日,[<Web 前端开发人员和设计师必读文章>系列十二]和大家见面了.梦想天空博客关注 前端开发 技术,分享各种增强网站用户体验的 jQuery 插件,展示前沿的 HT ...

随机推荐

  1. JS读取/创建本地文件及目录文件夹的方法

    原文链接:http://www.cnblogs.com/ayan/archive/2013/04/22/3036072.html 注:以下操作只在IE下有效! Javascript是网页制作中离不开的 ...

  2. 04.移植u-boot

    1.读readme获取信息    1.1 由Building the Software可知,需修改顶层makefile,指定架构和编译器    ifeq ($(HOSTARCH),$(ARCH))   ...

  3. [SaltStack] Minion-conf自动更新

    minion-conf配置文件自动更新, 加载 minion-conf是每个minion自身以来的配置, 为了方便我们在中心管控机上(Master)统一配置, 然后下发文件, 进而使得Minion能够 ...

  4. RadioGroup动态添加RadioButton,并且获得事件

    由于有许多的RadioButton是动态的,不是固定的一些,所以需要在代码中,动态的添加到RadioGroup中,下面是我的实现方法. 1.添加RadioButton到RadioGroup中 Radi ...

  5. 首次尝试Flink的一些感受

    最近打算研究研究 Flink,根据官方文档写个 Hello,World.入门还是比较容易的,不需要复杂的安装环境.配置.这篇文章简单介绍 Flink 的使用感受以及入门. 感受 搭建环境方便:Flin ...

  6. svn报“Previous operation has not finished; run 'cleanup' if it was interrupted”的错误

    -.叙述 今天需要更新接口文檔,所以就update了一下,結果報了如下錯誤:      Error : Previous operation has not finished; run 'cleanu ...

  7. Single Number III - LeetCode

    Given an array of numbers nums, in which exactly two elements appear only once and all the other ele ...

  8. [JLOI2015]有意义的字符串

    4002: [JLOI2015]有意义的字符串 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1000  Solved: 436[Submit][St ...

  9. Linux内核Crash分析

    转载自:http://linux.cn/article-3475-1.html 在工作中经常会遇到一些内核crash的情况,本文就是根据内核出现crash后的打印信息,对其进行了分析,使用的内核版本为 ...

  10. UIScrollView/UITableView 一直显示滚动条(ScrollBar Indicators)、滚动条Width(宽度)、滚动条Color(颜色)

    在 IOS 中,对 UIScrollView 的滚动条(ScrollBar Indicators)的自定义设置接口,一直都是很少的.除了能自定义简单的样式(UIScrollViewIndicatorS ...