以敏捷/BDD 方式在 Django 中使用 Doctests 的示例

发布于 2024-08-15 02:45:49 字数 1003 浏览 6 评论 0原文

我有兴趣学习如何以更敏捷/BDD 的方式进行文档测试和单元测试。 我发现了一些看似合理的教程,但它们只是缩略图。 我真正想看到的是一些采用 BDD 风格开发的 Django 项目的源代码。

我不清楚的是如何处理请求对象等。 我遇到过这样的情况:我已经部署了应用程序,但在生产中得到的行为与在开发中甚至从生产服务器上的 Python shell 中得到的行为完全不同。我希望一些文档测试能够帮助我诊断这一点,并为首先编写测试的更敏捷的过程打开大门。

具体来说,这是我尝试测试的代码:

def match_pictures_with_products( queryset, number_of_images = 3):      
    products = []  
    i = 0    
    for product in queryset:  
       if i < ( number_of_images ):  
           image =  product.imagemain_set.all()[:1]  
           product.photo_url = image[0].photo.url  

       products.append(product)  
       i += 1  

    return products  

def index(request):  
    """returns the top 10 most clicked products"""     
    products = Product.objects.all()[:10]  
    products = match_pictures_with_products( products, 10)  .  
    return render_to_response('products/product_list.html', {'products': products}) 

如何创建确保索引返回 10 个对象的 Doctest?
产品查询似乎在生产服务器上的 shell 中运行良好。实际服务器根本不返回任何产品。

I'm interested in learning how to Doctests and Unit tests in a more Agile / BDD way.
I've found a few tutorials that seem reasonable, but they are just thumbnails.
What I would really like to see is the source code of some Django projects that were developed BDD style.

The things I'm unclear about are how do you handle request objects etc.
I have a situation where I have deployed my app and I'm getting completely different behavior in production that I did in development or even from the Python shell on the production server. I'm hoping some Doctests will help me diagnose this and well as open the door for a more Agile process of writing the tests first.

Specifically, here is the code I'm trying to test:

def match_pictures_with_products( queryset, number_of_images = 3):      
    products = []  
    i = 0    
    for product in queryset:  
       if i < ( number_of_images ):  
           image =  product.imagemain_set.all()[:1]  
           product.photo_url = image[0].photo.url  

       products.append(product)  
       i += 1  

    return products  

def index(request):  
    """returns the top 10 most clicked products"""     
    products = Product.objects.all()[:10]  
    products = match_pictures_with_products( products, 10)  .  
    return render_to_response('products/product_list.html', {'products': products}) 

How do I create a Doctest that ensures that index returns 10 objects?
The Product queries seem to work fine from the shell on the production server. The actual server is not returning any products at all.

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

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

发布评论

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

评论(4

自控 2024-08-22 02:45:50

我以前也问过自己同样的问题。我发现文档测试对于视图、模型方法和管理器等内容的实用性有限,因为

  1. 您需要能够设置和拆卸测试数据集以实际用于测试
  2. 视图需要获取请求对象。在文档测试中,它来自哪里?

因此,我一直使用 Django 单元测试 框架为您处理这一切。但不幸的是,您无法获得文档测试的一些好处,并且这使得 TDD/BDD 更难实现。接下来是关于如何完成这项工作的纯粹猜测

我认为您希望从各自的模块和函数中获取文档测试,并在单元测试框架内执行它们。这将负责测试数据的设置/拆卸。如果您的文档测试是从 Django 的 unittest.TestCase 子类的测试方法中执行的,那么它们就能够使用该测试数据库。您还可以将模拟请求对象传递到文档测试的执行上下文中。这是一个 Django 片段,它提供了一个模拟请求对象和 信息。假设您想要测试所有应用程序视图中的文档字符串。你可以在tests.py中做这样的事情:

from ??? import RequestFactory
from doctest import testmod, DocTestFailure
from django.test import TestCase

from myapp import views

class MyAppTest(TestCase):

    fixtures = ['test_data.json']

    def test_doctests(self):                
        try:
            testmod(views, extraglobs={
                'REQUEST': RequestFactory()
            }, raise_on_error=True)
        except DocTestFailure, e:
            self.fail(e)

应该允许你做这样的事情:

def index(request):  
    """
    returns the top 10 most clicked products

    >>> response = index(REQUEST)
    >>> [test response content here]

    """     
    products = Product.objects.all()[:10]  
    products = match_pictures_with_products( products, 10)  .  
    return render_to_response('products/product_list.html', {'products': products})

同样,这只是我的想法,根本没有经过测试,但这是唯一的方法我认为您不需要将所有视图测试都放在单元测试框架中就可以实现您想要的效果。

I've asked myself the same question before. I've found doctests to be of limited utility for things like views, model methods and managers because

  1. You need to be able to setup and teardown a test data set to actually use for testing
  2. Views need to take a request object. In a doctest, where does that come from?

For that reason, I've always used the Django unit testing framework which handles all this for you. Unfortunately, though, you don't get some of the benefits of the doctests and it makes TDD/BDD harder to do. What follows next is pure speculation about how you might make this work:

I think you'd want to grab doctests from their respective modules and functions and execute them within the unit testing framework. This would take care of test data setup/teardown. If your doctests were executed from within a test method of something that subclasses Django's unittest.TestCase they'd be able to use that test DB. You'd also be able to pass a mock request object into the doc test's execution context. Here's a Django snippet that provides a mock request object and info on it. Let's say you wanted to test the docstrings from all of an applications views. You could do something like this in tests.py :

from ??? import RequestFactory
from doctest import testmod, DocTestFailure
from django.test import TestCase

from myapp import views

class MyAppTest(TestCase):

    fixtures = ['test_data.json']

    def test_doctests(self):                
        try:
            testmod(views, extraglobs={
                'REQUEST': RequestFactory()
            }, raise_on_error=True)
        except DocTestFailure, e:
            self.fail(e)

This should allow you to do something like this:

def index(request):  
    """
    returns the top 10 most clicked products

    >>> response = index(REQUEST)
    >>> [test response content here]

    """     
    products = Product.objects.all()[:10]  
    products = match_pictures_with_products( products, 10)  .  
    return render_to_response('products/product_list.html', {'products': products})

Again, this is just off the top of my head and not at all tested, but it's the only way that I think you could what you want without just putting all your view tests in the unit testing framework.

谜兔 2024-08-22 02:45:50

您的观点的编写方式很难测试。您必须抓取 html 来查看您想要的内容是否存在,然后您测试的内容会超出您的需要。更好的方法是重写您的视图以使其更易于测试。首先参数化您的模板名称,以便您可以创建一个简单的测试模板:

def index(request, template_name='products/product_list.html'):  
    """returns the top 10 most clicked products"""     
    products = Product.objects.all()[:10]  
    products = match_pictures_with_products( products, 10)  .  
    return render_to_response(template_name, {'products': products})

然后您可以编写一个仅计算产品数量的简单模板:

{{ products.count }} 

并确保模板返回“10”。

The way your view is written, it would be hard to test. You'd have to scrape the html to see if the content you want is present, and then you're testing more than you need to. Better would be to rewrite your view to make it easier to test. Start by parameterizing your template name, so you can create a simple test template:

def index(request, template_name='products/product_list.html'):  
    """returns the top 10 most clicked products"""     
    products = Product.objects.all()[:10]  
    products = match_pictures_with_products( products, 10)  .  
    return render_to_response(template_name, {'products': products})

Then you can write a simple template that just counts the number of products:

{{ products.count }} 

And make sure the template returns "10".

阪姬 2024-08-22 02:45:50

您可以使用 django testclient 和测试设置的上下文变量:

>>> response = client.get('/foo/')
>>> response.context['name']
'Arthur'

您还可以检查响应代码以确保页面返回成功 200

You can use the django testclient and test the context variables that get set:

>>> response = client.get('/foo/')
>>> response.context['name']
'Arthur'

You can also check the response code to make sure the page returned a success 200.

旧人 2024-08-22 02:45:50

zope.testbrowser 包可能在您的文档测试中有用,因为您想分析呈现生产服务器的 HTML 答案。

The zope.testbrowser package might be useful in your doctests, since you want to analyse the rendered HTML answer of your production server.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文