如何在django中使用验证码字段对表单进行单元测试?

时间:2010-07-01 15:31:07

标签: python django unit-testing captcha

我想通过对表单进行单元测试django视图。问题是这个表单有一个验证码字段(基于django-simple-captcha)。

from django import forms
from captcha.fields import CaptchaField

class ContactForm(forms.forms.Form):
    """
    The information needed for being able to download
    """
    lastname = forms.CharField(max_length=30, label='Last name')
    firstname = forms.CharField(max_length=30, label='First name')
    ...
    captcha = CaptchaField()

测试代码:

class ContactFormTest(TestCase):

    def test_submitform(self):
        """Test that the contact page"""
        url = reverse('contact_form')

        form_data = {}
        form_data['firstname'] = 'Paul'
        form_data['lastname'] = 'Macca'
        form_data['captcha'] = '28if'

        response = self.client.post(url, form_data, follow=True)

是否有任何方法对这些代码进行单元测试并在测试时摆脱验证码?

提前致谢

7 个答案:

答案 0 :(得分:16)

我知道这是一个旧帖子,但是django-simple-captcha现在有一个设置CAPTCHA_TEST_MODE,如果你提供值'PASSED',它会使验证码成功。您只需确保为两个验证码输入字段发送内容:

post_data['captcha_0'] = 'dummy-value'
post_data['captcha_1'] = 'PASSED'
self.client.post(url, data=post_data)

CAPTCHA_TEST_MODE设置只应在测试期间使用。我的settings.py:

if 'test' in sys.argv:
    CAPTCHA_TEST_MODE = True 

答案 1 :(得分:7)

这是我绕过它的方式。导入实际包含验证码信息的模型:

from captcha.models import CaptchaStore

首先,我检查测试验证码表是否为空:

captcha_count = CaptchaStore.objects.count()
self.failUnlessEqual(captcha_count, 0)

加载页面后(在这种情况下,它是一个注册页面),检查是否有新的验证码对象实例:

captcha_count = CaptchaStore.objects.count()
self.failUnlessEqual(captcha_count, 1)

然后,我检索验证码实例数据并使用表单POST。在我的例子中,POST期望'captcha_0'包含hashkey,'captcha_1'包含响应。

captcha = CaptchaStore.objects.all()[0]
registration_data = { # other registration data here
                     'captcha_0': captcha.hashkey,
                     'captcha_1': captcha.response }

如果在运行此测试之前启动CaptchaStore实例,则可能需要稍微调整一下。希望有所帮助。

答案 2 :(得分:1)

一种解决方案是设置“测试”,无论是真还是假。然后只是

if not testing:
   # do captcha stuff here

简单易用,易于切换。

答案 3 :(得分:1)

另一种解决方案类似于Jim McGaw的答案,但不需要空表CaptchaStore表。

captcha = CaptchaStore.objects.get(hashkey=CaptchaStore.generate_key())

registration_data = { # other registration data here
                 'captcha_0': captcha.hashkey,
                 'captcha_1': captcha.response }

这将为该测试生成新的验证码。

答案 4 :(得分:1)

我通过模拟ReCaptchaField对其进行了单元测试。首先,我在构造函数中添加了recaptcha字段。不能将其添加为常规字段,因为您将无法对其进行模拟(一旦在应用模拟之前对代码进行了评估):

class MyForm(forms.ModelForm):

    ...

    def __init__(self, *args, **kwargs):
        # Add captcha in the constructor to allow mock it
        self.fields["captcha"] = ReCaptchaField()

然后,我将ReCaptchaField替换为不需要的CharField。这样,我相信django-recaptcha会起作用。我只能测试自己的东西:

@mock.patch("trials.forms.ReCaptchaField", lambda: CharField(required=False))
def test_my_stuff(self):
    response = self.client.post(self.url, data_without_captcha)
    self.assert_my_response_fit_the_needs(response)

答案 5 :(得分:0)

采用与Jim McGaw类似的方法,但使用BeautifulSoup:

from captcha.models import CaptchaStore
from BeautifulSoup import BeautifulSoup

data = {...} #The data to post
soup = BeautifulSoup(self.client.get(url).content)
for field_name in ('captcha_0', ...): #get fields from the form
    data[field_name] = soup.find('input',{'name':field_name})['value']
captcha = CaptchaStore.objects.get(hashkey=data['captcha_0'])
data['captcha_1'] = captcha.challenge
response = self.client.post(url, data=data)

# check the results
...

答案 6 :(得分:0)

这是我们如何做到的。

@patch("captcha.fields.ReCaptchaField.validate")
def test_contact_view(self, validate_method):

    response = self.client.get(reverse("contact"))
    self.assertEqual(response.status_code, 200)

    data = {
        "name": "Bob Johnson",
        "email": "big_johnson@home.com",
        "phone": "800-212-2001",
        "subject": "I want Axis!",
        "message": "This is a giant\nThree liner..\nLove ya\n",
        "captcha": "XXX",
    }
    validate_method.return_value = True
    response = self.client.post(reverse("contact"), data=data)

    self.assertEqual(response.status_code, 302)