pytest_pytest入门

pytest

Pytest is my preferred Python testing library. It makes simple tests incredibly easy to write, and is full of advanced features (and tons of plugins) that help with more advanced testing scenarios.

Pytest是我首选的Python测试库。 它使简单的测试难以置信地易于编写,并具有高级功能(以及大量的插件),可帮助实现更高级的测试方案。

To demonstrate the basics, I’m going to walk through how I’d solve the first couple cryptopals challenges in a test-driven style, using py.test.

为了演示基础知识,我将逐步介绍如何使用py.test以测试驱动的方式解决前几个密码学家的挑战

Spoiler alert:

扰流板警报:

I’m going to spoil the first challenge, and maybe a bit of the second, below. If you want to work through them yourself, do that before reading the rest of this post.

我要破坏第一个挑战,或者说是下面的第二个挑战。 如果您想自己解决这些问题,请先阅读本文的其余部分。

安装和首次测试 (Installation and a first test)

Installation is typical:

典型安装:


$ pip install pytest

Note

注意

I’m using Python 3.5, and I’m doing all this in a virtualenv. If you don’t have Python installed, or don’t already know how to use pip and virtualenv, check out The Hitchiker’s Guide to Python for a good installation guide.

我正在使用Python 3.5,并且正在virtualenv中完成所有这些操作。 如果您没有安装Python,或者尚不知道如何使用pipvirtualenv ,请查阅《 The Hitchiker's Python指南》以获取良好的安装指南。

The first challenge asks us to convert a hex-encoded string to base64. I’ll start by writing a test to represent the challenge. py.test by default looks for tests in a files named something like test_whatever.py, so I’ll make a test_set1.py and write my test there:

一个挑战要求我们将十六进制编码的字符串转换为base64。 我将从编写代表挑战的测试开始。 py.test默认情况下会在名为test_whatever.py之类的文件中查找测试,因此我将创建一个test_set1.py并在其中编写测试:

import import base64

base64

def def test_challenge1test_challenge1 ():
    ():
    given given = = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"
    "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d"
    expected expected = = bb "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t"
    "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t"
    assert assert base64base64 .. b64encodeb64encode (( bytesbytes .. fromhexfromhex (( givengiven )) )) == == expected
expected

Did I get it right?

我说对了吗?


$ py.test
=============================================== test session starts ================================================
platform darwin -- Python 3.5.2, pytest-3.0.4, py-1.4.31, pluggy-0.4.0
rootdir: /Users/jacobkaplan-moss/c/pytest-blog, inifile:
collected 1 items

test_set1.py .

Yes, I haven’t really written any code yet: the first challenge is super-simple in Python, which can parse a hex-encoded string to a bytestring using bytes.fromhex, and has base64 encoding build-in as the base64 module.

是的,我还没有真正编写任何代码:第一个挑战是Python中的超级简单,它可以使用bytes.fromhex将十六进制编码的字符串解析为字节字符串,并具有base64编码内置作为base64模块。

However, this demonstrates the “simple” part of pytest: tests are just simple functions named test_whatever(), and rather than having than a bunch of assert methods (assertEqual, assertNotEqual, assertAlmostEqual), you just write simple assert statements.

但是,这证明了pytest的“简单”部分:测试只是名为test_whatever()的简单函数,而不是只有一堆assert方法( assertEqualassertNotEqualassertAlmostEqual ),您只需编写简单的assert语句即可。

第二,更现实的测试情况 (A second, more realistic testing situation)

To see a more complete example, I’ll solve the second challenge, which asks to implement a function that XORs two fixed-length buffers. In test-driven style, I’ll write the test first:

为了看到更完整的示例,我将解决第二个挑战,该挑战要求实现一个对两个固定长度缓冲区进行XOR的函数。 以测试驱动的方式,我将首先编写测试:

In typical test-driven style, I’ll now immediately run tests:

以典型的测试驱动样式,我现在将立即运行测试:


$ py.test

====================================================== ERRORS ======================================================
__________________________________________ ERROR collecting test_set1.py ___________________________________________
ImportError while importing test module '/Users/jacobkaplan-moss/c/pytest-blog/test_set1.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test_set1.py:2: in <module>
    from cryptopals import fixed_xor
E   ImportError: No module named 'cryptopals'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1 error in 0.12 seconds

As expected, I get an error – I haven’t created the cryptopals module the test tries to import. This error looks different from a failed test because this is happening during what pytest calls the “collection” phase. This is when pytest walks through your files, looking for test modules (files named test_whatever.py) and test functions (def test_whatever()). For more on how pytest discovers tests (and how to customize it), see conventions for Python test discovery.

不出所料,我收到一个错误–我尚未创建测试尝试导入的cryptopals模块。 这个错误看起来与失败的测试不同,因为这在pytest称为“收集”阶段期间发生。 这是pytest遍历文件,查找测试模块(名为test_whatever.py的文件)和测试函数( def test_whatever() )的时候。 有关pytest如何发现测试(以及如何对其进行自定义)的更多信息,请参见Python测试发现的约定

I’ll now stub out this function, mostly to demonstrate what test failure looks like. In cryptopals.py, I wrote:

现在,我将对该功能进行存根,主要是为了演示测试失败的样子。 在cryptopals.py中 ,我写道:

def def fixed_xorfixed_xor (( bs1bs1 , , bs2bs2 ):
    ):
    return return bb ''
''

And, as expected, I get a failure:

而且,正如预期的那样,我失败了:


$ py.test -q
.F
===================================================== FAILURES =====================================================
_________________________________________________ test_challenge2 __________________________________________________

    def test_challenge2():
        bs1 = bytes.fromhex("1c0111001f010100061a024b53535009181c")
        bs2 = bytes.fromhex("686974207468652062756c6c277320657965")
>       assert fixed_xor(bs1, bs2).hex() == "746865206b696420646f6e277420706c6179"
E       assert '' == '746865206b696420646f6e277420706c6179'
E         + 746865206b696420646f6e277420706c6179

test_set1.py:12: AssertionError
1 failed, 1 passed in 0.04 seconds

(I’m using -q – short for --quiet – to get slightly less output.)

(我使用-q--quiet的缩写–以获得更少的输出。)

I love the way that this highlights the line where the test failed on, and shows me the values of what that assert statement ran on. pytest is doing some tremendously dark black magic to make this happen, and the result is super-great.

我喜欢这种方式突出显示测试失败所在的行,并向我显示assert语句所运行的值。 pytest正在做一些非常暗黑的魔术来做到这一点,结果是非常出色的。

Once I write the correct code (omitted here in the spirit of keeping these challenges challenging), I should see the following:

一旦我编写了正确的代码(出于保持这些挑战的挑战性而在此省略),我应该看到以下内容:


$ py.test -q
..
2 passed in 0.01 seconds

体验更高级的pytest:参数化测试功能 (A taste of more advanced pytest: parameterized test functions)

For a final example, as a way of looking at a slightly more complex use of pytest, I want to write a few more test to check what happens when my fixed_xor function gets fed bytestrings of different lengths. The challenge only says that the function should “takes two equal-length buffers”, but doesn’t specify what happens when those buffers aren’t the same length. So, I made the decision that the result should be the length of the shortest bytestring (mostly because that makes the function easier to write).

作为最后一个示例,作为查看pytest稍微更复杂的用法的一种方式 ,我想编写更多测试以检查我的fixed_xor函数获取不同长度的字节时发生了什么。 挑战仅表明该函数应“采用两个相等长度的缓冲区”,但未指定当这些缓冲区的长度不同时会发生什么。 因此,我决定将结果设为最短字节串的长度(主要是因为这会使函数更易于编写)。

To test this properly, I should test against a few different scenarios: bs1 being shorter than bs2, len(bs2) < len(bs1), and where either bs1 or bs2 are empty – corner cases are always where bugs lurk! I could write four more test functions, but that’s repetitive. So I’ll turn to parameterized test functions:

为了正确地进行测试,我应该针对几种不同的情况进行测试: bs1bs2短, len(bs2)<len(bs1) ,并且bs1bs2为空–总是出现错误的地方! 我可以再编写四个测试函数,但这是重复的。 因此,我将转向参数化测试功能

This is the general pattern for doing more advanced work in pytest: use a decorator to somehow annotate or modify the test function to do something special. Here, the parametrize decorator lets me specify a list of arguments to be passed to the test function; the test function will then be run once for each set of parameters. Notice what happens when I run the tests:

这是在pytest中进行更高级工作的一般模式:使用装饰器以某种方式注释或修改测试函数以执行某些特殊操作。 在这里, 参数装饰器让我指定了要传递给测试函数的参数列表。 然后,将对每组参数运行一次测试功能。 注意运行测试时会发生什么:


$ py.test -q
.......
7 passed in 0.01 seconds

Rather than just showing test_challenge2_mismatching_lengths as a single test, we see five tests – one for each example. Because each set of parameters shows up as a separate case, if I add another example designed to deliberately fail, I’ll just see that one failure, and know exactly what it was:

我们看到五个测试,而不只是将test_challenge2_mismatching_lengths显示为一个测试,每个示例一个。 因为每组参数都显示为单独的情况,所以如果我添加另一个设计为故意失败的示例,那么我只会看到一个失败,并确切知道它是什么:


$ py.test -q
.......F
===================================================== FAILURES =====================================================
_________________________ test_challenge2_mismatching_lengths[1c011100-68697420-12345678] __________________________

in1 = '1c011100', in2 = '68697420', expected = '12345678'

    @pytest.mark.parametrize("in1, in2, expected", [
        ("1c011100", "686974207468652062756c6c277320657965", "74686520"),
        ("", "68697420", ""),
        ("", "68697420", ""),
        ("1c011100", "", ""),
        ("", "", ""),
        ("1c011100", "68697420", "12345678"),
    ])
    def test_challenge2_mismatching_lengths(in1, in2, expected):
        bs1 = bytes.fromhex(in1)
        bs2 = bytes.fromhex(in2)
>       assert fixed_xor(bs1, bs2) == bytes.fromhex(expected)
E       assert b'the ' == b'x124Vx'
E         At index 0 diff: 116 != 18
E         Full diff:
E         - b'the '
E         + b'x124Vx'

test_set1.py:26: AssertionError
1 failed, 7 passed in 0.05 seconds

pytest is full of niceties like this – different ways to easily manage setup/teardown scenarios, ways to share resources between different test modules, tons of options on how to organize and factor test code, ways to group and mark tests, and so on. It’s a great library that really makes writing test code easy and pleasant. I hope you’ll check it out!

pytest充满了这样的优点–轻松管理设置/拆卸方案的不同方法,在不同测试模块之间共享资源的方法,有关如何组织和分解测试代码的大量选项,对测试进行分组和标记的方法等等。 这是一个很棒的库,确实使编写测试代码变得轻松而愉快。 希望您能检查一下!

翻译自: https://www.pybloggers.com/2016/11/getting-started-with-pytest/

pytest

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值