python预期库

pyexpect的Python项目详细描述


pyexpect:expect模式的最小但非常灵活的实现

expect模式的全部要点是允许生成可预测的良好错误消息的简明断言。

最好在示例中查看:

>>> expect(3).to.equal(4)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "expect.py", line 146, in __call__
AssertionError: Expect 3 to equal 4

行噪声被尽可能地减少,因此错误消息显示在尽可能靠近有问题的代码的地方。没有堆栈跟踪来挖掘、清除和一致的错误消息,告诉您出了什么问题。这就是断言的工作原理。

为什么要在self.assert*上使用expect()呢?

与python unittest模块使用的经典断言模式相比,这是最好的解释。除此之外,这些断言可以独立于任何unittest包使用。但让我们从一个例子开始:

self.assertEquals('foo', 'bar')

在这个断言中,不可能看到哪个参数是预期的,哪个是实际的值。虽然这个顺序在unittest包中的不同断言之间基本上是内部一致的(遗憾的是,大多数情况下是这样),但是在python中所有不同的单元测试包之间,尤其是在不同语言之间,它并不一致,这个模式已经被实现了。已启用。

更糟糕的是,一些框架会输出如下错误消息: (是的,我在看你!)

'bar' does not equal 'foo'

很容易花上几分钟的时间,直到你记起或者弄明白你的框架欺骗了你,并颠倒了参数的顺序,只是让你更难理解你正在阅读的代码。

如果你和我一样对此感到恼火,请允许我向你介绍expect模式。这样的断言:

expect('foo').to.equal('bar')
# or this
expect('foo').equals('bar')
# or even this
expect('foo') == 'bar'

使它绝对明白什么是预期的和什么是实际的价值。 不可能混淆。同时,错误消息被设计成清晰地映射回 到源代码:

Expect 'foo' to equal 'bar'.

因此,错误信息的映射是即时和完整的,每次都可以节省您几分钟的时间,提高您的专注度、工作效率,以及在使用单元测试时的最重要的乐趣。

另外,所有这些异常都没有耦合到任何testcase类,因此您可以轻松地在代码中的任何位置重用它们,以形式化代码对某些内部状态的期望。有时称为"按合同设计"或"快速失败"编程。哦,而且这些期望通常更短,所以您在测试中输入的断言更清晰、更切题,甚至更少。就像吃蛋糕一样!

有趣!那它能做什么呢?

很高兴你这么问!给您:

  1. 许多包含的匹配器:查看源代码以查看开始所需的所有断言。从等于并且提升直到匹配-我们已经覆盖了您。不仅如此,每个匹配器都有一些别名,因此您可以使用在断言中读得最好的变量,或者在跨语言边界使用多个单元测试框架时更习惯使用这种变量(python/js anyone?)

    一些示例:

    expect(True).is_.true()
    expect(True).is_true()
    expect(True).equals(True)
    expect(True).is_.equal(True)
    expect(True) == True
    expect(raising_calable).raises()
    expect(raising_calable).to_raise()
    

    如果缺少重要别名,欢迎请求拉取。

  2. 易用性:expect()可以任意链接您可以想到的任何内容(只要它是有效的python标识符),以便尽可能清晰地描述断言:

    expect(23).to.equal(23)
    expect(23).is_.equal(23)
    # or go all out - but just because it works doesn't mean it's sensible
    expect(23).to_be_chaned.with_something.that_makes_sense_in\
        .your_context.before_it.calls_the.matcher.as_the_last.segment(23)
    # Here .segment(23) would be the matcher that is called
    

    选择对您的特定测试有意义的内容,以便以后阅读测试时感觉很自然,并尽可能地传递代码的含义。

  3. 扩展的简单性:在我看过的所有其他python expect实现中,至少它们的某些方面要复杂得多。每个匹配器都是一个类或一些需要通过或多或少复杂的过程注册的东西,参数不仅仅是简单的方法参数,不是不支持作为本机框架概念…

    与PyExpect相比,如果您想注册一个新的匹配器,则可以很容易地定义一个方法,然后将其分配给任意多个实例方法名,断言您想在其中断言的内容,并明确定义将引发的错误消息:

    def falseish(self):
        # See expect() source for availeable helpers
        self._assert(self._actual == False, "to be falseish")
    expect.is_falsish = expect.is_falseish = expect.falsish = expect.falseish = falseish
    

    类预期(原始预期): 定义错误(自我): #有关可用的帮助程序,请参见expect()source self._assert(self._actual==false,"以假乱真")

    完成了!

    还要注意匹配器如何清楚地传达重要的信息:它断言什么,以及它生成什么错误消息。不含绒毛™!

    相比之下,您可以将匹配器添加到更为成熟的包中,如sure确保-我认为pyexpect更简单-您可以只在expect或使用更多方法创建本地子类。

  4. nativenot支持:如果您定义了匹配器,则不必定义它的逆,也不必执行任何特殊的操作来获取它。这意味着,对于每一个匹配者,比如等于,都会自动得到与之相反的结果,即不等于。这个逆过程可以通过多种方式调用:

    您可以在匹配器前面加上而不是这样的前缀

    expect(foo).not_equals(bar)
    expect(some_function).not_to_raise()
    

    您可以将not作为matcher前面路径的一部分,如下所示:

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    0

    也就是说,您可以在标识符的开头、中间或结尾包含单词而不是-只需确保通过snakecase将其与标识符分开即可。

    这适用于每个匹配器的所有别名,因此不需要额外的工作。

    有关更多示例,请查看匹配器的测试套件。

    如果要添加自己的匹配项,如果将期望实现为多个连续检查,则有时反向操作不会自动工作。在这种情况下,反向匹配器可能会断言错误的内容,因为在反向情况下,检查的顺序没有意义。如果发生这种情况,请查看expect.\u assert_if_positive()expect.\u assert_if_negative()expect.\u is_negative()。不过,请注意,好的配对者只需要很少的时间。

  5. 伟大的错误消息:pyexpect非常小心地确保遇到错误的每个方面都尽可能简洁和有用。所有错误消息的格式都相同,总是以预期的格式开头,然后由匹配者自定义,以尽可能多地打包信息。

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    1

    如果您编写自己的断言方法来增强单元测试,则很容易获得长堆栈跟踪,因为实际断言会在一个调用的匹配器中发生一些堆栈帧。

    考虑一下这样的断言(有点杜撰,好吧。但我相信您在您的项目中看到过这种情况:

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    2

    它将提供如下输出:

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    3

    即使在这种简单的情况下,实际误差也会从实际误差中去掉4行。

    使用pyexpect进行如下测试:

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    4

    提供此输出(标准unittest.main()):

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    5

    在鼻测试中:

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    6

    py.test这更漂亮:

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    7

    注意,实际的matchersometing()调用另一个方法\u assert来执行实际的断言并合成错误消息,但是这些在堆栈跟踪中都不可见?对于您在matcher中调用的任何方法都是这样的,所以调用您的api或您需要触发断言并享受生成的错误消息的可读性的任何东西。

    另一个真正难以读取的错误消息的常见原因是消息太长。有过这样的经历吗?

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    8

    祝你好运预期对象和实际对象的输出甚至是分开的,更不用说它们之间的区别了。

    pyexpect在多行中格式化长错误消息,因此您总能看到投诉从何处开始,并在精神上更轻松地分散这两个对象:

    >>> expect(3).to.equal(4)
    Traceback (most recent call last):
      File "<input>", line 1, in <module>
      File "expect.py", line 146, in __call__
    AssertionError: Expect 3 to equal 4
    
    9

    tl;dr:错误信息更容易阅读,而且错误和引起你分心的原因之间的差别也更小。应该是这样。

  6. 单元测试之外的用法:可以将此包用作一个独立的断言包,它提供了比仅使用assert和优化的错误消息来引导更具表现力的断言。

    只要在需要的地方断言就可以通过快速失败获得健壮的代码:

    self.assertEquals('foo', 'bar')
    
    0

    如果需要,可以将断言从抛出切换到返回(bool,string)元组,以便在api中重用它。

    self.assertEquals('foo', 'bar')
    
    1

    如果需要,可以重写生成的错误消息,而无需更改匹配器。有关详细信息,请参见expect.with_message()

  7. 测试覆盖率:当然,pyexpect有完整的测试覆盖率,确保它完全符合您的预期。

  8. 你认为这个文档中有更好的东西吗?发送拉取请求。:)< >

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java为什么javaassist仅在项目中使用lambda时加载Entitymanager时抛出无效的常量类型:18   java如何识别用户是否在Alexa中首次启动技能?   java maven:如何防止插件更新   java StringBuilder将null追加为“null”   在java中,我可以在画布上绘制画布吗?   java如何在JRadioButton上垂直对齐文本和图像?   java“类是对象的集合”。这个定义是对的还是错的?   java如何用其他字符替换字符串中的1个或多个字符?   Java的HashSet<Double>及其子集的hashcode的唯一性   对象ArrayList的java并发修改错误   多线程Java线程:让EDT函数等待长时间运行的函数离开EDT   java如何重写方法,将一个实例变量和一个局部变量相加,从而生成一个数据类型为Double的新变量?