【问题标题】:Do I need to use mocks?我需要使用模拟吗?
【发布时间】:2019-01-02 11:52:27
【问题描述】:

我有处理来自 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)

【问题讨论】:

    标签: python unit-testing testing integration-testing


    【解决方案1】:

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

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

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

    单元测试应该验证单个组件的功能,并且不应该依赖任何外部服务。集成测试验证代码与其他组件一起正确运行,并且通常仅在验证了各个组件的完整性后才会执行。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-16
      • 2015-07-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-24
      • 2016-04-12
      相关资源
      最近更新 更多