我需要使用模拟吗?

时间:2019-01-02 11:52:27

标签: python unit-testing testing integration-testing

我具有处理Slack中特定机器人事件的功能。一般来说,用户单击一个按钮,然后我的服务器就会接收并处理该按钮的有效载荷。

问题是我应该如何测试?我需要模拟make_adminbuild_admins_message并检查它们是否被调用,还是需要测试真实的实现?例如,我可以从数据库中检索用户并检查它实际上是管理员,还可以检查build_admins_message是否返回了我希望接收的字典。

@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)

1 个答案:

答案 0 :(得分:3)

这里的问题有两个。首先,您必须验证代码是否可以在正常运行的Slack服务器上正常工作-正如您所推论的那样,模拟是实现此目的的一种好方法,因为单元测试应该完全独立。您还可以编写模拟来模拟功能不正确的服务器的行为。

但是,这可能会导致您的模拟无法正确模拟Slack服务器的行为,因此即使代码通过了单元测试,您的代码也无法在现实生活中运行。为此,您将需要 integration 测试以验证(如您当前的测试类所显示的那样)该代码可在Slack服务器上正常工作。

创建模拟对象时,您甚至可以捕获成功交易的网络流量,然后通过修补较低级别的组件以生成适当的网络级响应以避免与服务器交互来使用该内容生成模拟响应。由于您通常没有能力修改生产服务器以方便测试,因此模拟通常是验证对异常服务器响应的正确处理的最简单方法。这完全取决于您要走多远。

单元测试应验证单个组件的功能,并且不应依赖任何外部服务。集成测试可以验证代码是否可以与其他组件一起正常工作,并且通常只有在验证了各个组件的完整性之后才能执行。

测试是一个非常大的主题,所以我希望这能回答您的问题。