我正在尝试针对Django中的某些代码构建一些单元测试,这些代码运行针对第三方API的操作。具体来说,我正在使用MailChimp同步一些用户数据并使用实现MailChimp API的库。
我有一个自定义类MailChimpAPI
,它基本上充当我正在使用的Python库的瘦包装器。以下是代码的一些相关部分:
class MailChimpAPI(object):
"""
A wrapper for implementing business logic and exception handling around
the PyChimp API
"""
...
def __init__(self, api_key, primary_list_id, merge_keys, use_secure=True, timeout=None):
...
# setup api
self.api_key = api_key
self.api = PyChimp(self.api_key)
...
...
def _call(self, method_name, args=[], kwargs={}):
"""Calls the PyChimp API directly"""
result = getattr(self.api, method_name)(*args, **kwargs)
if self.api.errorCode:
self._raise_mailchimp_exception()
else:
return result
...
我剪掉了(...)实现业务逻辑等的大部分代码,但这里的突出方面是我将api
属性设置为PyChimp(第三方库)的实例在__init__()
中,对该库的所有实际调用均在_call()
函数中进行。
我对单元测试有些新意,所以我很难找到解决这个问题的最佳方法。我的一个想法是在我的类之外实例化PyChimp库并将其传递给构造函数。另一个想法是测试这个我可以模拟_call
方法,以便它不会碰到实际的库。
我遇到的首要问题是,显然,我不想针对实际的API执行任何测试代码。因此,我试图找出“存根”或“模拟”该API的最佳方法,以便在测试期间对其进行的调用实际上不会执行。理想情况下,我希望在Django测试套件中运行所有测试时都存在该模拟API。例如,我正在探索在通过post_save
信号创建用户帐户时将用户同步到MailChimp的可能性。因此,我显然不希望Django身份验证应用程序中运行的测试触发实际的API。
我希望Django有一些全局设置/拆卸钩子或我可以使用的信号,但似乎没有任何东西。
有没有人建议如何在测试过程中用假装干净地替换“实时”API?或者我完全错了吗?
我非常有信心可以破解我的解决方案,但如果有人能够分享一些关于采用这种方式的“最佳”方式的智慧,那就太棒了。
答案 0 :(得分:1)
最好的方法可能是你建议的,在外面创建api对象并将其传递给构造函数。这将允许您轻松替换api类进行测试。
您可以创建一个MockPyChimp类,它具有与实际PyChimp api相同的方法。这样,您可以轻松地在测试中重用相同的模拟类。
我对python / django单元测试不够熟悉,能够建议任何特定的库来协助这一点,但我认为存在某种模拟库等。
答案 1 :(得分:0)
在Python中“模拟”函数调用的最佳方法是使用mock库。此外,如果您使用nose作为单元测试框架,那么值得考虑的插件是nose-blockage,如果您的测试没有正确模拟所有内容,则确保没有API调用通过。