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

发布于 2024-09-07 11:24:42 字数 888 浏览 3 评论 0原文

我想通过提交表单来对 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)

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

提前致谢

I would like to unit test a django view by sumitting a form. The problem is that this form has a captcha field (based on 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()

The test code:

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)

Is there any approach to unit-test this code and get rid of the captcha when testing?

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

吖咩 2024-09-14 11:24:42

我知道这是一篇旧文章,但 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 设置仅应在测试期间使用。我的设置.py:

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

I know this is an old post, but django-simple-captcha now has a setting CAPTCHA_TEST_MODE which makes the captcha succeed if you supply the value 'PASSED'. You just have to make sure to send something for both of the captcha input fields:

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

The CAPTCHA_TEST_MODE setting should only be used during tests. My settings.py:

if 'test' in sys.argv:
    CAPTCHA_TEST_MODE = True 
泛滥成性 2024-09-14 11:24:42

这是我解决这个问题的方法。导入实际保存验证码信息的模型:

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 期望“captcha_0”包含哈希键,“captcha_1”包含响应。

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

如果您在运行此测试之前从 CaptchaStore 实例开始,您可能需要对此进行一些调整。希望有帮助。

Here's the way I got around it. Import the model that actually holds Captcha info:

from captcha.models import CaptchaStore

First, I check that the test captcha table is empty:

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

After loading the page (in this case, it's a registration page), check that there's a new captcha object instance:

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

Then, I retrieve the captcha instance data and POST that with the form. In my case, the POST expects 'captcha_0' to contain the hashkey, and 'captcha_1' to contain the response.

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

You may need to tweak this a little if you start with CaptchaStore instances before you run this test. Hope that helps.

最冷一天 2024-09-14 11:24:42

我们是这样做的。

@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": "[email protected]",
        "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)

Here is how we do it.

@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": "[email protected]",
        "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)
终弃我 2024-09-14 11:24:42

我通过模拟 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)

I unit tested it by mocking the ReCaptchaField. First, I've added the recaptcha field in the constructor. It cannot be added as a regular field because you won't be able to mock it (once the code is evaluated before the mock is being applied):

class MyForm(forms.ModelForm):

    ...

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

Then, I just replaced the ReCaptchaField by a not required CharField. This way, I'm trusting django-recaptcha will work. I can test only my own stuff:

@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)
ゝ杯具 2024-09-14 11:24:42

一种解决方案是设置“测试”,该值要么为真,要么为假。然后就很

if not testing:
   # do captcha stuff here

简单了,而且切换也很容易。

One solution is have a setting "testing" that is either true or false. And then just

if not testing:
   # do captcha stuff here

It's simple and easy, and an easy toggle.

甜是你 2024-09-14 11:24:42

另一个解决方案类似于 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 }

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

Another solutions which is similar to Jim McGaw's answer but remove the need of empty table CaptchaStore table.

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

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

This will generate new captcha just for that test.

七七 2024-09-14 11:24:42

这是唯一对我有用的方法,

在测试设置方法中设置 CAPTCHA_TEST_MODE=True 。

class ApplicationTestCase(TestCase):
    def setUp(self):
        self.client = Client()
        self.url = reverse('application')
        from captcha.conf import settings as captcha_settings
        captcha_settings.CAPTCHA_TEST_MODE = True
    
    def test_post_valid_form(self):
        data = {
            'name': 'John Doe',
            "captcha_0": "8e10ebf60c5f23fd6e6a9959853730cd69062a15",
            "captcha_1": "PASSED",
        }

        response = self.client.post(self.url, data)
        self.assertEqual(response.status_code, 200)

Here is the only thing that worked for me,

set the CAPTCHA_TEST_MODE=True in the test setup method.

class ApplicationTestCase(TestCase):
    def setUp(self):
        self.client = Client()
        self.url = reverse('application')
        from captcha.conf import settings as captcha_settings
        captcha_settings.CAPTCHA_TEST_MODE = True
    
    def test_post_valid_form(self):
        data = {
            'name': 'John Doe',
            "captcha_0": "8e10ebf60c5f23fd6e6a9959853730cd69062a15",
            "captcha_1": "PASSED",
        }

        response = self.client.post(self.url, data)
        self.assertEqual(response.status_code, 200)
吐个泡泡 2024-09-14 11:24:42

采用与 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
...

With a similar approach than Jim McGaw but using 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
...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文