Django可测试地基于test / prod / dev上下文设置客户端库

时间:2015-12-04 21:15:39

标签: django testing configuration

我在创建新用户对象时从后端调用特定CRM(Streak)。由于新的用户对象是在测试期间集体创建的,所以我们的CRM会被新的虚拟用户填充。这是一个我想要解决的轻微痛苦。

这是我的产品Streak客户:

class StreakClient(object):
    # bunch of stuff here
    def setup_client(self, client):
        #production API integration code here
        return response['boxKey']

这就是我想要的:

  1. 测试不实际进行生产调用。
  2. 反例:测试该客户端类本身。我有一个需要与生产Streak一起使用的TestStreakClient测试用例。
  3. 现在有许多已经实施的各种测试,默认调用生产代码路径。虽然我可以这样做,但如果它是一个很好的长期练习,我宁愿不必返回并添加一堆setUp方法。
  4. 我的问题是:

      

    我应该如何允许StreakClient和DummyStreakClient类   被定义为以上是可能的吗?

    我查看了邮局的mail.py,他们似乎根据设置文件中的字符串动态导入模块:

    def get_mailbox(self)
        klass = import_string(settings.MAIL_BACKEND)
        return klass()
    

    但这让我觉得有点奇怪......除非它不是。我当然可以创建一个新的虚拟Streak客户端并以某种方式加载它。我可以进行单元测试/模拟。也许别的什么?

    需要注意的其他事项 - 没有代码真正关心setup_client的返回值。所以我真的不需要在这里完全拦截调用和模拟路径 - 根据需要,crm对象创建成功或失败。

2 个答案:

答案 0 :(得分:0)

  1. 如果Streak没有沙盒api(用于测试),那么你必须创建假的Streak服务器(检查Pretenders库)并对其进行测试,这是针对集成,组件和end2end测试。由于单元测试必须单独工作,因此依赖于StreakClient的所有内容都必须模拟该StreakClient。
  2. StreakClient的单元测试在这里不能很好地完成。 IMO你应该对它进行集成测试,设置假的Streak服务器并测试该类。单元测试需要快速并在一个进程中运行,这意味着您必须模拟http库甚至更深层次的套接字。这并不好,因为在你不知情的情况下改变lib实现时,嘲笑你不拥有的lib会导致maintanance问题。
  3. PS。设置客户端看起来像副作用函数(命令),因此它不应该返回任何内容。

答案 1 :(得分:0)

我决定通过让所有环境调用prod(测试除外)来做出具体的设计妥协(在我的情况下这很好)。

然后我创建了一个名为SafeTestCase的自定义测试用例超类,并使所有相关的测试类继承自它(相当少量的重构工作)。现在所有SafeTestCase都可以安全地分配一个模拟DummyStreaker,因此实际上不会发生这种情况。

在真正的Streaker类的实际集成测试中,我只是不从该测试用例/类继承并让生产调用发生。

class DummyStreaker(crm.Streaker):
    def setup_client(self, client):
        return "dummy-streak-box-key"


class SafeTestCase(TestCase):
    def setUp(self):
        self.streaker_patch = patch('offerdrive.modeldir.crm.Streaker', DummyStreaker)
        self.addCleanup(self.streaker_patch.stop)
        self.streaker_patch = self.streaker_patch.start()

    def test_setup_worked(self):
        self.assertIs(crm.Streaker, self.streaker_patch)