Pytest 存储预期数据的位置 [英] Pytest where to store expected data

查看:30
本文介绍了Pytest 存储预期数据的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

测试函数我需要传递参数并查看输出是否与预期输出匹配.

Testing function I need to pass parameters and see the output matches the expected output.

当函数的响应只是一个可以在测试函数内部定义的小数组或单行字符串时,这很容易,但假设函数 I test 修改了一个可能很大的配置文件.或者如果我明确定义它,结果数组有 4 行长.我应该把它存放在哪里,以便我的测试保持干净且易于维护?

It is easy when function's response is just a small array or a one-line string which can be defined inside the test function, but suppose function I test modifies a config file which can be huge. Or the resulting array is something 4 lines long if I define it explicitly. Where do I store that so my tests remain clean and easy to maintain?

现在,如果那是字符串,我只是在 .py 测试附近放一个文件,然后在测试中执行 open() :

Right now if that is string I just put a file near the .py test and do open() it inside the test:

def test_if_it_works():
    with open('expected_asnwer_from_some_function.txt') as res_file:
        expected_data = res_file.read()
    input_data = ... # Maybe loaded from a file as well
    assert expected_data == if_it_works(input_data)

我发现这种方法有很多问题,比如保持这个文件是最新的问题.它看起来也很糟糕.我可以让事情变得更好,将它移到固定装置上:

I see many problems with such approach, like the problem of maintaining this file up to date. It looks bad as well. I can make things probably better moving this to a fixture:

@pytest.fixture
def expected_data()
    with open('expected_asnwer_from_some_function.txt') as res_file:
        expected_data = res_file.read()
    return expected_data

@pytest.fixture
def input_data()
    return '1,2,3,4'

def test_if_it_works(input_data, expected_data):
    assert expected_data == if_it_works(input_data)

这只是将问题移到另一个地方,通常我需要测试函数在空输入、输入单个项目或多个项目的情况下是否有效,所以我应该创建一个包含所有三个案例或多个夹具的大夹具.最终代码变得相当混乱.

That just moves the problem to another place and usually I need to test if function works in case of empty input, input with a single item or multiple items, so I should create one big fixture including all three cases or multiple fixtures. In the end code gets quite messy.

如果一个函数需要一个复杂的字典作为输入或者返回同样大尺寸的字典,那么测试代码就会变得丑陋:

If a function expects a complicated dictionary as an input or gives back the dictionary of the same huge size test code becomes ugly:

 @pytest.fixture
 def input_data():
     # It's just an example
     return {['one_value': 3, 'one_value': 3, 'one_value': 3,
     'anotherky': 3, 'somedata': 'somestring'], 
      ['login': 3, 'ip_address': 32, 'value': 53, 
      'one_value': 3], ['one_vae': 3, 'password': 13, 'lue': 3]}

阅读带有此类装置的测试并使其保持最新状态非常困难.

It's quite hard to read tests with such fixtures and keep them up to date.

搜索一段时间后,我找到了一个库,它解决了部分问题,而不是大的配置文件,我有大的 HTML 响应.这是betamax.

After searching a while I found a library which solved a part of a problem when instead of big config files I had large HTML responses. It's betamax.

为了更容易使用,我创建了一个装置:

For easier usage I created a fixture:

from betamax import Betamax

@pytest.fixture
def session(request):
    session = requests.Session()
    recorder = Betamax(session)
    recorder.use_cassette(os.path.join(os.path.dirname(__file__), 'fixtures', request.function.__name__)
    recorder.start()
    request.addfinalizer(recorder.stop)
    return session

所以现在在我的测试中我只使用 session 夹具,我提出的每个请求都会自动序列化到 fixtures/test_name.json 文件,所以下次我执行测试而不是执行真正的 HTTP 请求库从文件系统加载它:

So now in my tests I just use the session fixture and every request I make is being serialized automatically to the fixtures/test_name.json file so the next time I execute the test instead of doing a real HTTP request library loads it from the filesystem:

def test_if_response_is_ok(session):
   r = session.get("http://google.com")

这非常方便,因为为了使这些装置保持最新状态,我只需要清理 fixtures 文件夹并重新运行我的测试.

It's quite handy because in order to keep these fixtures up to date I just need to clean the fixtures folder and rerun my tests.

推荐答案

我曾经遇到过类似的问题,我必须针对预期文件测试配置文件.这就是我修复它的方式:

I had a similar problem once, where I have to test configuration file against an expected file. That's how I fixed it:

  1. 在相同位置创建一个与测试模块同名的文件夹.将所有需要的文件放在该文件夹中.

  1. Create a folder with the same name of your test module and at the same location. Put all your expected files inside that folder.

test_foo/
    expected_config_1.ini
    expected_config_2.ini
test_foo.py

  • 创建一个夹具,负责将这个文件夹的内容移动到一个临时文件中.我确实使用了 tmpdir 固定装置来解决这个问题.

  • Create a fixture responsible for moving the contents of this folder to a temporary file. I did use of tmpdir fixture for this matter.

    from __future__ import unicode_literals
    from distutils import dir_util
    from pytest import fixture
    import os
    
    
    @fixture
    def datadir(tmpdir, request):
        '''
        Fixture responsible for searching a folder with the same name of test
        module and, if available, moving all contents to a temporary directory so
        tests can use them freely.
        '''
        filename = request.module.__file__
        test_dir, _ = os.path.splitext(filename)
    
        if os.path.isdir(test_dir):
            dir_util.copy_tree(test_dir, bytes(tmpdir))
    
        return tmpdir
    

    重要提示:如果您使用的是 Python 3,请将 dir_util.copy_tree(test_dir, bytes(tmpdir)) 替换为 dir_util.copy_tree(test_dir, str(tmpdir)).

    Important: If you are using Python 3, replace dir_util.copy_tree(test_dir, bytes(tmpdir)) with dir_util.copy_tree(test_dir, str(tmpdir)).

    使用您的新装置.

    def test_foo(datadir):
        expected_config_1 = datadir.join('expected_config_1.ini')
        expected_config_2 = datadir.join('expected_config_2.ini')
    

  • 请记住:datadirtmpdir 夹具相同,另外还具有处理放置在具有测试模块名称的文件夹中的预期文件的能力.

    Remember: datadir is just the same as tmpdir fixture, plus the ability of working with your expected files placed into the a folder with the very name of test module.

    这篇关于Pytest 存储预期数据的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆