我应该在每个测试中断言相同的值吗?
Should I assert the same values in every test?
我有简单的 class 和 public build
我想测试的方法。目前,我在每个测试中断言它 returns 的所有值。这是一种好的做法,还是我应该为静态值编写一个测试,而在其他测试中只检查根据输入而变化的值?
实施
class FiltersAttachment:
TYPE_OPTIONS = [
{"text": "All types", "value": "all"},
{"text": ":link: Webpages", "value": "web_pages"}
]
STATUS_OPTIONS = [
{"text": "Available / Unavailable", "value": "all"},
{"text": ":white_circle: Available", "value": "available"},
{"text": ":red_circle: Unavailable", "value": "unavailable"}
]
@classmethod
def _filter_options(cls, options, selected):
return list(filter(lambda t: t['value'] == selected, options))
@classmethod
def build(cls, check_type='', status=''):
return {
'fallback': 'Filters',
'callback_id': 'resource_filters',
'color': '#d2dde1',
'mrkdwn_in': ['text'],
'actions': [
{
'name': 'resource_type',
'text': 'Type',
'type': 'select',
'options': cls.TYPE_OPTIONS,
'selected_options': cls._filter_options(
cls.TYPE_OPTIONS, check_type)
},
{
'name': 'resource_status',
'text': 'Status',
'type': 'select',
'options': cls.STATUS_OPTIONS,
'selected_options': cls._filter_options(
cls.STATUS_OPTIONS, status)
}
]
}
测试
class TestFiltersAttachment(TestCase):
def assert_attachment(self, attachment):
self.assertEqual(attachment['fallback'], 'Filters')
self.assertEqual(attachment['callback_id'], 'resource_filters')
self.assertEqual(attachment['color'], '#d2dde1')
self.assertEqual(attachment['mrkdwn_in'], ['text'])
type_action = attachment['actions'][0]
self.assertEqual(type_action['name'], 'resource_type')
self.assertEqual(type_action['text'], 'Type')
self.assertEqual(type_action['type'], 'select')
self.assertEqual(type_action['options'][0]['text'], 'All types')
self.assertEqual(type_action['options'][0]['value'], 'all')
self.assertEqual(type_action['options'][1]['text'], ':link: Webpages')
self.assertEqual(type_action['options'][1]['value'], 'web_pages')
status_action = attachment['actions'][1]
self.assertEqual(status_action['name'], 'resource_status')
self.assertEqual(status_action['text'], 'Status')
self.assertEqual(status_action['type'], 'select')
self.assertEqual(status_action['options'][0]['text'], 'Available / Unavailable')
self.assertEqual(status_action['options'][0]['value'], 'all')
self.assertEqual(status_action['options'][1]['text'], ':white_circle: Available')
self.assertEqual(status_action['options'][1]['value'], 'available')
self.assertEqual(status_action['options'][2]['text'], ':red_circle: Unavailable')
self.assertEqual(status_action['options'][2]['value'], 'unavailable')
def test_all_type_selected(self):
attachment = FiltersAttachment.build(check_type='all')
self.assert_attachment(attachment)
selected_type = attachment['actions'][0]['selected_options'][0]
self.assertEqual(selected_type['text'], 'All types')
self.assertEqual(selected_type['value'], 'all')
def test_all_status_selected(self):
attachment = FiltersAttachment.build(status='all')
self.assert_attachment(attachment)
selected_status = attachment['actions'][1]['selected_options'][0]
self.assertEqual(selected_status['text'], 'Available / Unavailable')
self.assertEqual(selected_status['value'], 'all')
...
测试套件质量的标准之一是,测试套件在测试失败的情况下如何支持您识别问题。理想情况下,您应该能够通过查看哪些测试失败和哪些没有失败来单独识别问题。您应该不需要使用调试器来找出实际出错的地方。
您编写测试的方式不会给您最好的支持。您在一个测试函数中打包了许多断言。因此,测试功能会因多种原因而失败,当您看到其中一个功能失败时,您将不得不进行详细分析或使用调试来找出失败的原因。当让你的测试冗余地检查方面时(正如你在问题中所问的那样),你会让它们更加不具体,这会使问题变得更糟。
因此,每个测试都应该检查一个特定的方面,这样一个测试的失败给出了最具体的信息。这是通过结合以下两个原则来实现的:
- 每个测试应验证一个特定方面。
- 同一方面不应该有多余的测试。
在所谓的参数化测试的帮助下,可以方便地将每个断言转化为自己的测试。 Python 的一些提示可以在这个问题中找到:How do you generate dynamic (parameterized) unit tests in python?
我有简单的 class 和 public build
我想测试的方法。目前,我在每个测试中断言它 returns 的所有值。这是一种好的做法,还是我应该为静态值编写一个测试,而在其他测试中只检查根据输入而变化的值?
实施
class FiltersAttachment:
TYPE_OPTIONS = [
{"text": "All types", "value": "all"},
{"text": ":link: Webpages", "value": "web_pages"}
]
STATUS_OPTIONS = [
{"text": "Available / Unavailable", "value": "all"},
{"text": ":white_circle: Available", "value": "available"},
{"text": ":red_circle: Unavailable", "value": "unavailable"}
]
@classmethod
def _filter_options(cls, options, selected):
return list(filter(lambda t: t['value'] == selected, options))
@classmethod
def build(cls, check_type='', status=''):
return {
'fallback': 'Filters',
'callback_id': 'resource_filters',
'color': '#d2dde1',
'mrkdwn_in': ['text'],
'actions': [
{
'name': 'resource_type',
'text': 'Type',
'type': 'select',
'options': cls.TYPE_OPTIONS,
'selected_options': cls._filter_options(
cls.TYPE_OPTIONS, check_type)
},
{
'name': 'resource_status',
'text': 'Status',
'type': 'select',
'options': cls.STATUS_OPTIONS,
'selected_options': cls._filter_options(
cls.STATUS_OPTIONS, status)
}
]
}
测试
class TestFiltersAttachment(TestCase):
def assert_attachment(self, attachment):
self.assertEqual(attachment['fallback'], 'Filters')
self.assertEqual(attachment['callback_id'], 'resource_filters')
self.assertEqual(attachment['color'], '#d2dde1')
self.assertEqual(attachment['mrkdwn_in'], ['text'])
type_action = attachment['actions'][0]
self.assertEqual(type_action['name'], 'resource_type')
self.assertEqual(type_action['text'], 'Type')
self.assertEqual(type_action['type'], 'select')
self.assertEqual(type_action['options'][0]['text'], 'All types')
self.assertEqual(type_action['options'][0]['value'], 'all')
self.assertEqual(type_action['options'][1]['text'], ':link: Webpages')
self.assertEqual(type_action['options'][1]['value'], 'web_pages')
status_action = attachment['actions'][1]
self.assertEqual(status_action['name'], 'resource_status')
self.assertEqual(status_action['text'], 'Status')
self.assertEqual(status_action['type'], 'select')
self.assertEqual(status_action['options'][0]['text'], 'Available / Unavailable')
self.assertEqual(status_action['options'][0]['value'], 'all')
self.assertEqual(status_action['options'][1]['text'], ':white_circle: Available')
self.assertEqual(status_action['options'][1]['value'], 'available')
self.assertEqual(status_action['options'][2]['text'], ':red_circle: Unavailable')
self.assertEqual(status_action['options'][2]['value'], 'unavailable')
def test_all_type_selected(self):
attachment = FiltersAttachment.build(check_type='all')
self.assert_attachment(attachment)
selected_type = attachment['actions'][0]['selected_options'][0]
self.assertEqual(selected_type['text'], 'All types')
self.assertEqual(selected_type['value'], 'all')
def test_all_status_selected(self):
attachment = FiltersAttachment.build(status='all')
self.assert_attachment(attachment)
selected_status = attachment['actions'][1]['selected_options'][0]
self.assertEqual(selected_status['text'], 'Available / Unavailable')
self.assertEqual(selected_status['value'], 'all')
...
测试套件质量的标准之一是,测试套件在测试失败的情况下如何支持您识别问题。理想情况下,您应该能够通过查看哪些测试失败和哪些没有失败来单独识别问题。您应该不需要使用调试器来找出实际出错的地方。
您编写测试的方式不会给您最好的支持。您在一个测试函数中打包了许多断言。因此,测试功能会因多种原因而失败,当您看到其中一个功能失败时,您将不得不进行详细分析或使用调试来找出失败的原因。当让你的测试冗余地检查方面时(正如你在问题中所问的那样),你会让它们更加不具体,这会使问题变得更糟。
因此,每个测试都应该检查一个特定的方面,这样一个测试的失败给出了最具体的信息。这是通过结合以下两个原则来实现的:
- 每个测试应验证一个特定方面。
- 同一方面不应该有多余的测试。
在所谓的参数化测试的帮助下,可以方便地将每个断言转化为自己的测试。 Python 的一些提示可以在这个问题中找到:How do you generate dynamic (parameterized) unit tests in python?