在不重复代码的情况下测试 Flask WTForms 验证器
Testing Flask WTForms validators without repeating code
我使用 Flask 和 WTForms 以及标准和自定义表单验证器编写了一个相对简单的 Web 应用程序。我现在正在努力学习 Python 测试。我编写了以下 tests.py 文件,它可以与 unittest 一起正常工作,但有冗余。有没有更好、更有效、更 pythonic (DNRY) 的方法来做到这一点?我看过一些 pytest 教程,想知道固定装置是否有帮助,但我不太理解它们。而且我假设有一种更 pythonic 的方法可以用 unittest 来做到这一点。看来我需要一种方法来传递不同的 dict 参数,但我不知道该怎么做。
from fly_app import app
import unittest
class FlaskTestCase(unittest.TestCase):
def test_city_code(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="xxxx"))
self.assertIn(b'That does not appear to be a valid city code', response.data)
def test_code_pairs(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="HFD", destination="CAS"))
self.assertIn(b'This origin-destination pair is not in searchable cache', response.data)
def test_duration_range(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="MSP", destination="NYC", min_duration=20))
self.assertIn(b'Number must be between 1 and 15', response.data)
def test_duration_integer(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="MSP", destination="NYC", min_duration='abc'))
self.assertIn(b'Not a valid integer value', response.data)
def test_duration_pair(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="MSP", destination="NYC", min_duration=10, max_duration=7))
self.assertIn(b'Maximum trip length cannot be less than minimum', response.data)
if __name__ == "__main__":
unittest.main()
我建议您创建自定义断言器方法 (assertExtensiveFlightSearchGivesError(self, data, expected_error_message)
) 以删除一些重复项:
class FlaskTestCase(unittest.TestCase):
def assertExtensiveFlightSearchGivesError(self, data, expected_error_message):
response = test_client.post("/flight_search/extensive", data=data)
self.assertEqual(4xx, response.status_code)
self.assertIn(expected_error_message, response.data, "extensive flight search did not contain expected error message")
def test_city_code(self):
self.assertExtensiveFlightSearchGivesError(
{'origin': 'xxx'},
b'That does not appear to be a valid city code'
)
def test_code_pairs(self):
self.assertExtensiveFlightSearchGivesError(
{'origin': "HFD", 'destination': "CAS"},
b'This origin-destination pair is not in searchable cache'
)
# ... and so on
您也可以将所有测试用例收集在一起并使用 .subTest()
:
TEST_CASES = [
({'origin': 'xxx'}, b'That does not appear to be a valid city code'),
({'origin': "HFD", 'destination': "CAS"}, b'This origin-destination pair is not in searchable cache')
]
class FlaskTestCase2(unittest.TestCase):
def assertExtensiveFlightSearchGivesError(self, data, expected_error_message):
response = test_client.post("/flight_search/extensive", data=data)
self.assertEqual(4xx, response.status_code)
self.assertIn(expected_error_message, response.data, "extensive flight search did not contain expected error message")
def test_all_error_cases(self):
for data, expected_error_message in TEST_CASES:
with self.subTest():
self.assertExtensiveFlightSearchGivesError(data, expected_error_message)
但在您的情况下,IMO 最上面的代码示例更清晰。
我使用 Flask 和 WTForms 以及标准和自定义表单验证器编写了一个相对简单的 Web 应用程序。我现在正在努力学习 Python 测试。我编写了以下 tests.py 文件,它可以与 unittest 一起正常工作,但有冗余。有没有更好、更有效、更 pythonic (DNRY) 的方法来做到这一点?我看过一些 pytest 教程,想知道固定装置是否有帮助,但我不太理解它们。而且我假设有一种更 pythonic 的方法可以用 unittest 来做到这一点。看来我需要一种方法来传递不同的 dict 参数,但我不知道该怎么做。
from fly_app import app
import unittest
class FlaskTestCase(unittest.TestCase):
def test_city_code(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="xxxx"))
self.assertIn(b'That does not appear to be a valid city code', response.data)
def test_code_pairs(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="HFD", destination="CAS"))
self.assertIn(b'This origin-destination pair is not in searchable cache', response.data)
def test_duration_range(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="MSP", destination="NYC", min_duration=20))
self.assertIn(b'Number must be between 1 and 15', response.data)
def test_duration_integer(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="MSP", destination="NYC", min_duration='abc'))
self.assertIn(b'Not a valid integer value', response.data)
def test_duration_pair(self):
tester = app.test_client(self)
response = tester.post('/flight_search/extensive', data=dict(origin="MSP", destination="NYC", min_duration=10, max_duration=7))
self.assertIn(b'Maximum trip length cannot be less than minimum', response.data)
if __name__ == "__main__":
unittest.main()
我建议您创建自定义断言器方法 (assertExtensiveFlightSearchGivesError(self, data, expected_error_message)
) 以删除一些重复项:
class FlaskTestCase(unittest.TestCase):
def assertExtensiveFlightSearchGivesError(self, data, expected_error_message):
response = test_client.post("/flight_search/extensive", data=data)
self.assertEqual(4xx, response.status_code)
self.assertIn(expected_error_message, response.data, "extensive flight search did not contain expected error message")
def test_city_code(self):
self.assertExtensiveFlightSearchGivesError(
{'origin': 'xxx'},
b'That does not appear to be a valid city code'
)
def test_code_pairs(self):
self.assertExtensiveFlightSearchGivesError(
{'origin': "HFD", 'destination': "CAS"},
b'This origin-destination pair is not in searchable cache'
)
# ... and so on
您也可以将所有测试用例收集在一起并使用 .subTest()
:
TEST_CASES = [
({'origin': 'xxx'}, b'That does not appear to be a valid city code'),
({'origin': "HFD", 'destination': "CAS"}, b'This origin-destination pair is not in searchable cache')
]
class FlaskTestCase2(unittest.TestCase):
def assertExtensiveFlightSearchGivesError(self, data, expected_error_message):
response = test_client.post("/flight_search/extensive", data=data)
self.assertEqual(4xx, response.status_code)
self.assertIn(expected_error_message, response.data, "extensive flight search did not contain expected error message")
def test_all_error_cases(self):
for data, expected_error_message in TEST_CASES:
with self.subTest():
self.assertExtensiveFlightSearchGivesError(data, expected_error_message)
但在您的情况下,IMO 最上面的代码示例更清晰。