如何在Python中生成一个用于单元测试的虚假HTTP请求对象?

huangapple go评论76阅读模式
英文:

How to generate a fake HTTP request object for unit test in Python?

问题

在Python Django项目中,我们想要编写一个单元测试来向要测试的函数中发送HTTP POST请求。下面的cURL示例命令显示了我们的测试设置。

cURL方法从Web服务器的端点开始并触发整个逻辑路径,但我们希望单元测试专注于接受request参数的特定函数。我们从这篇帖子中获得了提示,其中包含以下用于测试的Python源代码示例来模拟HTTP请求。

我们的问题:

请参阅cURL命令的-d参数,我们想知道如何将请求正文传递给伪造的对象。

技术细节:

  • cURL命令:
curl http://127.0.0.1:8000/api/transaction/ --insecure \
    --verbose \
    -d '<env:Envelope ... >
  <env:Header>
    ...
  </env:Header>
  <env:Body>
    ...
  </env:Body>
</env:Envelope>'
  • 用于伪造HTTP请求的Python示例源代码:
from django.core.handlers.wsgi import WSGIRequest
from io import StringIO
from django.contrib.auth.models import AnonymousUser

def GetFakeRequest(path='/', user=None):
    """构造一个伪造的请求(WSGIRequest)对象"""
    req = WSGIRequest({
        'REQUEST_METHOD': 'GET',
        'PATH_INFO': path,
        'wsgi.input': StringIO()})

    req.user = AnonymousUser() if user is None else user
    return req
英文:

In a Python Django project, we want a unit test to feed a HTTP POST request into the function under test. The cURL sample command below shows our test settings.

The cURL approach starts from the web server's endpoint and triggers the entire logic path, but we want the unit test to focus on a specific function taking in the request argument. And, we got hint from this post with the below sample Python source code to fake a HTTP request for testing.

Our Question:

See the -d argument of the cURL command, we wonder how to feed the request body in the faked object.

Technical Details:

  • The cURL command:
curl http://127.0.0.1:8000/api/transaction/ --insecure \
    --verbose \
    -d '<env:Envelope ... >
  <env:Header>
    ...
  </env:Header>
  <env:Body>
    ...
  </env:Body>
</env:Envelope>
'
  • The Python sample source code for faking a HTTP request:
from django.core.handlers.wsgi import WSGIRequest
from io import StringIO
from django.contrib.auth.models import AnonymousUser

def GetFakeRequest(path='/', user=None):
    """ Construct a fake request(WSGIRequest) object"""
    req = WSGIRequest({
        'REQUEST_METHOD': 'GET',
        'PATH_INFO': path,
        'wsgi.input': StringIO()})

    req.user = AnonymousUser() if user is None else user
    return req

答案1

得分: 1

下面是您要翻译的内容:

也许一个替代方法是使用 RequestFactory 来构建 request 对象。然后使用类似参数的方式调用该函数。类似这样:

tests.py

from django.test import TestCase, RequestFactory
from django.contrib.auth import get_user_model

from myapp.views import my_function


class TestHTTPRequest(TestCase):
    def setUp(self):
        self.data = "<env:Envelope ... > \
                        <env:Header> \
                            ... \
                        </env:Header> \
                        <env:Body> \
                            ... \
                        </env:Body> \
                    </env:Envelope>"
        self.factory = RequestFactory()
        self.user = get_user_model().objects.create_user(
            username="john", email="john_doe@test.com", password="top_secret"
        )

    def test_some_function(self):
        request = self.factory.get("some/url/", data={'data': self.data})
        request.user = self.user

        response = my_function(request)

        self.assertEqual(response, "Some way to confirm success")

views.py

def my_function(request):
    data = request.GET.get('data')
    # print(f'The data: \n {data}')
    
    # print(request.user.email)

    return "Some way to confirm success"

我将其放在了视图内,但当然您可以将其放在任何您想要的地方。

英文:

Maybe an alternative is to build the request object using RequestFactory. And call the the function using such as param. Something like:

tests.py

from django.test import TestCase, RequestFactory
from django.contrib.auth import get_user_model

from myapp.views import my_function


class TestHTTPRequest(TestCase):
    def setUp(self) -&gt; None:
        self.data = &quot;&lt;env:Envelope ... &gt; \
                        &lt;env:Header&gt; \
                            ... \
                        &lt;/env:Header&gt; \
                        &lt;env:Body&gt; \
                            ... \
                        &lt;/env:Body&gt; \
                    &lt;/env:Envelope&gt;&quot;
        self.factory = RequestFactory()
        self.user = get_user_model().objects.create_user(
            username=&quot;john&quot;, email=&quot;john_doe@test.com&quot;, password=&quot;top_secret&quot;
        )

    def test_some_function(self):
        request = self.factory.get(&quot;some/url/&quot;, data={&#39;data&#39;: self.data})
        request.user = self.user

        response = my_function(request)

        self.assertEqual(response, &quot;Some way to confirm success&quot;)

views.py

def my_function(request):
    data = request.GET.get(&#39;data&#39;)
    # print(f&#39;The data: \n {data}&#39;)
    
    # print(request.user.email)

    return &quot;Some way to confirm success&quot;

I placed it inside views, but of course it can be anywhere you want.

huangapple
  • 本文由 发表于 2023年6月1日 03:07:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376568.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定