为Python REST API函数编写单元测试

2024-09-27 00:22:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在学习PythonRESTAPI(附带项目)。我一直在阅读RealPython、Python请求文档等的很多教程。我发现了这篇关于如何在Python(Correct way to try/except using Python requests module?)中正确编写try/except的文章。但有一件事仍然让我困惑,那就是如何为这样的函数创建一个单元测试,因为它不返回任何东西。有什么帮助吗

def google_do_something(blahblah):
    url='http://www.google.com/' + blahblah
    try:
        r = requests.get(url,timeout=3)
        r.raise_for_status()
    except requests.exceptions.HTTPError as errh:
        print (errh)
    except requests.exceptions.ConnectionError as errc:
        print (errc)
    except requests.exceptions.Timeout as errt:
        print (errt)
    except requests.exceptions.RequestException as err:
        print (err)

我可以想到这一点,但我不知道用什么来断言

def test_google_do_something():
    g = google_do_something('blahblah')
    # assert??

Tags: urldefasgooglerequestsdosomethingexceptions
3条回答

Python中有几个可用的单元测试框架。Try/except块对于错误处理很好,但是如果要对调用进行单元测试,仍然需要对调用进行单独的单元测试

您确实有一些可以测试的东西,您可以返回它并在单元测试中进行测试

使用unittest的单元测试示例:

import unittest
import requests

class RestCalls():

    def google_do_something(blahblah):
        url= blahblah
        try:
            r = requests.get(url,timeout=1)
            r.raise_for_status()
            return r.status_code
        except requests.exceptions.Timeout as errt:
            print (errt)
            raise
        except requests.exceptions.HTTPError as errh:
            print (errh)
            raise
        except requests.exceptions.ConnectionError as errc:
            print (errc)
            raise
        except requests.exceptions.RequestException as err:
            print (err)
            raise


class TestRESTMethods(unittest.TestCase):

    def test_valid_url(self):
        self.assertEqual(200,RestCalls.google_do_something('http://www.google.com/search'))

    def test_exception(self):
        self.assertRaises(requests.exceptions.Timeout,RestCalls.google_do_something,'http://localhost:28989')

if __name__ == '__main__':
    unittest.main()

执行时应显示(对此帖子进行了一些编辑,更新后的输出包含在帖子底部):

> python .\Tests.py
 .
                                   
Ran 1 test in 0.192s

OK

如果您声明了与请求不同的响应代码,它将失败(请求只是返回http响应代码):

python .\Tests.py
F
======================================================================
FAIL: test_upper (__main__.TestStringMethods)
                                   
Traceback (most recent call last):
  File ".\Tests.py", line 25, in test_upper
    self.assertEqual(404,RestCalls.google_do_something('search'))
AssertionError: 404 != 200

                                   
Ran 1 test in 0.245s

FAILED (failures=1)

这是意料之中的

编辑:包括异常测试。您可以通过在except块中包含raise来测试这些,该块将在运行后显示:

> python .\Tests.py
HTTPConnectionPool(host='localhost', port=28989): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x03688598>, 'Connection to localhost timed out. (connect timeout=1)'))
..
                                   
Ran 2 tests in 2.216s

OK

参考资料:

我不确定您的方法是否是一个好主意(只是在出现错误时打印一些内容),但您可以模拟print函数,看看它是否真的被调用(以及使用了哪些参数):

https://docs.python.org/3/library/unittest.mock.html?highlight=mock#module-unittest.mock

编辑:

据我记忆所及,使用mock有点棘手。您必须在当前模块中模拟打印功能。可能是这样的(未测试…):

from unittest.mock import patch
from unittest import TestCase

class TestGoogleDoSomething(TestCase)
    
    @patch("nameOfYourModule.print")
    def test_google_do_something(self, print_mock): # the decorator will pass the mock object into the function
        g = google_do_something('blahblah')
        print_mock.assert_called_with("your error message here ...")

看起来您使用的是print而不是所有异常处理程序。我认为这不是一个好的做法。从我的角度来看,如果现在不确定如何处理这些异常,我更愿意再次提出这些异常

也就是说,当发生任何错误时,将抛出异常;如果没有异常,这意味着该函数工作良好。因此,您可以在此基础上设计单元测试用例

相关问题 更多 >

    热门问题