2017-08-28 79 views
3

我是初学者,在python中使用pytest并试图为以下方法编写测试用例,该方法在传递正确标识时获取用户地址,否则会自定义错误BadId。用于测试请求和响应的python pytest

def get_user_info(id: str, host='127.0.0.1', port=3000) -> str: 
    uri = 'http://{}:{}/users/{}'.format(host,port,id) 
    result = Requests.get(uri).json() 
    address = result.get('user',{}).get('address',None) 
    if address: 
     return address 
    else: 
     raise BadId 

有人可以帮助我,也可以建议我什么是学习pytest的最佳资源? TIA

+0

另外:问计资源被认为是题外话了所以,这里是我用来学习'pytest':[link](https://www.youtube.com/watch?v=l32bsaIDoWk&list=PLeo1K3hjS3utzQYDNRNluzqJqpMXx6hHu)[link](https://www.youtube.com/watch? v = UPanUFVFfzY)[link](https://www.youtube.com/watch?v=k99HS HQDsi4)。 –

+0

谢谢@RickTeachey指出错误和资源。 –

回答

2

您的测试方案可能看起来像这样。

首先我建议创建一个用于各种方法测试的夹具。夹具设置你的类的一个实例用于测试,而不是在测试本身中创建实例。以这种方式保持任务分离有助于使您的测试更健壮,更易于阅读。

from my_package import MyClass 
import pytest 

@pytest.fixture 
def a_test_object(): 
    return MyClass() 

您可以通过测试对象的一系列方法测试:

def test_something(a_test_object): 
    # do the test 

但是,如果您的测试对象在安装过程中需要的一些资源(如连接,数据库,文件等等等),你可以嘲笑它,以避免为测试设置资源。有关如何做到这一点的一些有用信息,请参阅this talk。顺便说一句:如果你需要测试几个不同的状态在你的灯具中创建的用户定义对象,你需要参数化你的灯具。这是一个复杂的主题,但文档explains fixture parametrization very clearly

您需要做的另一件事是确保任何.get调用Requests被拦截。这很重要,因为它允许您的测试在没有互联网连接的情况下运行,并确保它们不会因连接不良而失败,这不是您要测试的事情。

通过使用pytestmonkeypatch feature可以拦截Requests.get。所需要的只是包括monkeypatch作为测试方案功能的输入参数。

您可以使用另一个夹具来实现此目的。这可能是这样的:

import Requests 
import pytest 

@pytest.fixture 
def patched_requests(monkeypatch): 
    # store a reference to the old get method 
    old_get = Requests.get 
    def mocked_get(uri, *args, **kwargs): 
     '''A method replacing Requests.get 
     Returns either a mocked response object (with json method) 
     or the default response object if the uri doesn't match 
     one of those that have been supplied. 
     ''' 
     _, id = uri.split('/users/', 1) 
     try: 
      # attempt to get the correct mocked json method 
      json = dict(
      with_address1 = lambda: {'user': {'address': 123}}, 
      with_address2 = lambda: {'user': {'address': 456}}, 
      no_address = lambda: {'user': {}}, 
      no_user = lambda: {}, 
      )[id] 
     except KeyError: 
      # fall back to default behavior 
      obj = old_get(uri, *args, **kwargs) 
     else: 
      # create a mocked requests object 
      mock = type('MockedReq',(), {})() 
      # assign mocked json to requests.json 
      mock.json = json 
      # assign obj to mock 
      obj = mock 
     return obj 
    # finally, patch Requests.get with patched version 
    monkeypatch.setattr(Requests, 'get', mocked_get) 

这个看上去复杂,直到你明白发生了什么:我们只是做了一些嘲笑JSON对象(通过字典来表示)与预先确定的用户ID和地址。修补版本的Requests.get只需返回一个类型为MockedReq的对象 - 当请求其id时,将使用相应的嘲讽.json()方法。

注意Requests只会在实际使用上面的测试夹具修补,例如:

def test_something(patched_requests): 
    # use patched Requests.get 

任何测试不使用patched_requests作为输入参数,将不使用补丁版本。

另外请注意,您可以在测试本身中使用monkeypatch Requests,但我建议单独执行此操作。如果您使用请求API的其他部分,则可能还需要对这些部分进行修改。将所有这些东西分离开来往往比将其纳入测试更容易理解。

接下来写下你的各种方法测试。您需要针对方法的每个方面进行不同的测试。换句话说,通常你会为你的方法成功的实例写一个不同的测试,另一个测试失败的时候再测试一次。

首先我们用几个测试用例测试方法的成功。

@pytest.mark.parametrize('id, result', [ 
    ('with_address1', 123), 
    ('with_address2', 456), 
]) 
def test_get_user_info_success(patched_requests, a_test_object, id, result): 
    address = a_test_object.get_user_info(id) 
    assert address == result 

接下来我们可以测试提高使用with pytest.raises特征BadId例外。请注意,由于引发了异常,因此测试功能没有result输入参数。

@pytest.mark.parametrize('id', [ 
    'no_address', 
    'no_user', 
]) 
def test_get_user_info_failure(patched_requests, a_test_object, id): 
    from my_package import BadId 
    with pytest.raises(BadId): 
     address = a_test_object.get_user_info(id) 

,张贴在我的评论,在这里也有一些额外的资源,帮助您了解更多关于pytest:

link

link