我需要使用模拟吗?
Do I need to use mocks?
我有处理来自 Slack 的特定机器人事件的功能。一般来说,用户点击一个按钮然后我的服务器接收并处理这个按钮的负载。
问题是我应该如何测试它?我需要模拟 make_admin
和 build_admins_message
并检查它们是否被调用,或者我需要测试真实的实现吗?例如,我可以从数据库中检索用户并检查它实际上是管理员,还检查 build_admins_message returns 我希望收到的字典。
@slack_interactions.on('admin_add')
def handle_admin_add(payload):
team_id = payload['team']['id']
user_id = payload['user']['id']
action_value = payload['actions'][0]['selected_options'][0]['value']
user = SlackUser.objects.find_by_ids(team_id, action_value)
if user and not user.is_bot:
user.make_admin()
return build_admins_message(team_id, user_id)
目前我的测试是这样的:
class TestAdminAddHandler(TestCase):
def setUp(self):
team = SlackTeam.objects.create(team_id='TEAMID')
SlackUser.objects.create(team=team, user_id='USERID')
SlackUser.objects.create(team=team, user_id='BOTID', is_bot=True)
SlackUser.objects.create(
team=team, user_id='ADMINID', is_bot_admin=True)
def tearDown(self):
SlackUser.objects.all().delete()
SlackTeam.objects.all().delete()
def test_wrong_callback(self):
payload = {'callback_id': 'wrong_callback'}
message = handle_admin_add(payload)
self.assertIsNone(message)
def test_has_no_user(self):
payload = {
'callback_id': 'admin_add',
'team': {'id': 'TEAMID'},
'user': {'id': 'ADMINID'},
'actions': [{
'selected_options': [{'value': 'BADID'}]
}]
}
message = handle_admin_add(payload)
user = SlackUser.objects.get(user_id='USERID')
self.assertFalse(user.is_bot_admin)
for att in message['attachments']:
self.assertNotIn('BADID', att.get('title', ''))
def test_user_is_bot(self):
payload = {
'callback_id': 'admin_add',
'team': {'id': 'TEAMID'},
'user': {'id': 'ADMINID'},
'actions': [{
'selected_options': [{'value': 'BOTID'}]
}]
}
message = handle_admin_add(payload)
user = SlackUser.objects.get(user_id='BOTID')
self.assertFalse(user.is_bot_admin)
for att in message['attachments']:
self.assertNotIn('BOTID', att.get('title', ''))
def test_add_admin(self):
payload = {
'callback_id': 'admin_add',
'team': {'id': 'TEAMID'},
'user': {'id': 'ADMINID'},
'actions': [{
'selected_options': [{'value': 'USERID'}]
}]
}
message = handle_admin_add(payload)
user = SlackUser.objects.filter(user_id='USERID').first()
self.assertTrue(user.is_bot_admin)
user_in_list = False
for att in message['attachments']:
if 'USERID' in att.get('title', ''):
user_in_list = True
self.assertTrue(user_in_list)
这里的问题有两个。首先,您必须验证您的代码是否可以与正常运行的 Slack 服务器一起正常工作——正如您推断的那样,模拟将是执行此操作的好方法,因为单元测试应该是完全独立的。您还可以编写模拟来模拟功能不正常的服务器的行为。
但是,这可能会导致您的模拟无法正确模拟 Slack 服务器的行为,因此即使您的代码通过了单元测试,它也无法在现实生活中运行。为此,您需要 integration 测试来验证(正如您当前的测试 class 所显示的那样)代码是否可以在 Slack 服务器上正常工作。
创建模拟对象时,您甚至可以从成功的交易中捕获网络流量,然后使用该内容生成模拟响应,方法是修补较低级别的组件以生成适当的网络级别响应,以避免与服务器。由于您通常没有能力为测试方便而修改生产服务器,因此模拟通常是验证是否正确处理异常服务器响应的最简单方法。这完全取决于你想走多远。
单元测试应该验证单个组件的功能,而不应该依赖任何外部服务。集成测试验证代码与其他组件一起正常运行,通常只有在验证了各个组件的完整性后才会执行。
测试是一个很大的主题,所以我希望这能回答您的问题。
我有处理来自 Slack 的特定机器人事件的功能。一般来说,用户点击一个按钮然后我的服务器接收并处理这个按钮的负载。
问题是我应该如何测试它?我需要模拟 make_admin
和 build_admins_message
并检查它们是否被调用,或者我需要测试真实的实现吗?例如,我可以从数据库中检索用户并检查它实际上是管理员,还检查 build_admins_message returns 我希望收到的字典。
@slack_interactions.on('admin_add')
def handle_admin_add(payload):
team_id = payload['team']['id']
user_id = payload['user']['id']
action_value = payload['actions'][0]['selected_options'][0]['value']
user = SlackUser.objects.find_by_ids(team_id, action_value)
if user and not user.is_bot:
user.make_admin()
return build_admins_message(team_id, user_id)
目前我的测试是这样的:
class TestAdminAddHandler(TestCase):
def setUp(self):
team = SlackTeam.objects.create(team_id='TEAMID')
SlackUser.objects.create(team=team, user_id='USERID')
SlackUser.objects.create(team=team, user_id='BOTID', is_bot=True)
SlackUser.objects.create(
team=team, user_id='ADMINID', is_bot_admin=True)
def tearDown(self):
SlackUser.objects.all().delete()
SlackTeam.objects.all().delete()
def test_wrong_callback(self):
payload = {'callback_id': 'wrong_callback'}
message = handle_admin_add(payload)
self.assertIsNone(message)
def test_has_no_user(self):
payload = {
'callback_id': 'admin_add',
'team': {'id': 'TEAMID'},
'user': {'id': 'ADMINID'},
'actions': [{
'selected_options': [{'value': 'BADID'}]
}]
}
message = handle_admin_add(payload)
user = SlackUser.objects.get(user_id='USERID')
self.assertFalse(user.is_bot_admin)
for att in message['attachments']:
self.assertNotIn('BADID', att.get('title', ''))
def test_user_is_bot(self):
payload = {
'callback_id': 'admin_add',
'team': {'id': 'TEAMID'},
'user': {'id': 'ADMINID'},
'actions': [{
'selected_options': [{'value': 'BOTID'}]
}]
}
message = handle_admin_add(payload)
user = SlackUser.objects.get(user_id='BOTID')
self.assertFalse(user.is_bot_admin)
for att in message['attachments']:
self.assertNotIn('BOTID', att.get('title', ''))
def test_add_admin(self):
payload = {
'callback_id': 'admin_add',
'team': {'id': 'TEAMID'},
'user': {'id': 'ADMINID'},
'actions': [{
'selected_options': [{'value': 'USERID'}]
}]
}
message = handle_admin_add(payload)
user = SlackUser.objects.filter(user_id='USERID').first()
self.assertTrue(user.is_bot_admin)
user_in_list = False
for att in message['attachments']:
if 'USERID' in att.get('title', ''):
user_in_list = True
self.assertTrue(user_in_list)
这里的问题有两个。首先,您必须验证您的代码是否可以与正常运行的 Slack 服务器一起正常工作——正如您推断的那样,模拟将是执行此操作的好方法,因为单元测试应该是完全独立的。您还可以编写模拟来模拟功能不正常的服务器的行为。
但是,这可能会导致您的模拟无法正确模拟 Slack 服务器的行为,因此即使您的代码通过了单元测试,它也无法在现实生活中运行。为此,您需要 integration 测试来验证(正如您当前的测试 class 所显示的那样)代码是否可以在 Slack 服务器上正常工作。
创建模拟对象时,您甚至可以从成功的交易中捕获网络流量,然后使用该内容生成模拟响应,方法是修补较低级别的组件以生成适当的网络级别响应,以避免与服务器。由于您通常没有能力为测试方便而修改生产服务器,因此模拟通常是验证是否正确处理异常服务器响应的最简单方法。这完全取决于你想走多远。
单元测试应该验证单个组件的功能,而不应该依赖任何外部服务。集成测试验证代码与其他组件一起正常运行,通常只有在验证了各个组件的完整性后才会执行。
测试是一个很大的主题,所以我希望这能回答您的问题。