测试“不同层”的最佳做法是什么?在Django? [英] What are the best practices for testing "different layers" in Django?

查看:156
本文介绍了测试“不同层”的最佳做法是什么?在Django?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是不是新的测试,但对于Django中测试不同层次的建议的混乱感到困惑。

I'm NOT new to testing, but got really confused with the mess of recommendations for testing different layers in Django.

推荐(而且它们是正确的)避免模型中的 Doctests ,因为它们不可维护...

Some recommend (and they are right) to avoid Doctests in the model as they are not maintainable...

其他人说不要使用 fixtures ,因为它们比帮助函数更不灵活,例如..

Others say don't use fixtures, as they are less flexible than helper functions, for instance..

还有两组人谁争取使用 Mock 对象。第一组相信使用Mock并隔离系统的其余部分,而另一个组更喜欢停止模拟并开始测试

There are also two groups of people who fight for using Mock objects. The first group believe in using Mock and isolating the rest of the system, while another group prefer to Stop Mocking and start testing..

所有以上我已经提过,主要是关于测试模型。 功能测试是另一个故事(使用test.Client()VS webTest VS等)

All I have mentioned above, were mostly in regards to testing models. Functional testing is an another story (using test.Client() VS webTest VS etc. )

是否有任何可维护,可拆卸和适当的测试不同层次的方法?

Is there ANY maintainable, extandible and proper way for testing different layers??

更新

我知道 Carl Meyer的讲话在PyCon 2012 ..

I am aware of Carl Meyer's talk at PyCon 2012..

推荐答案

更新08-07-2012

我可以告诉你我单位测试的做法对于我自己的工作,我的工作相当不错,我会给你我的理由:

I can tell you my practices for unit testing that are working pretty well for my own ends and I'll give you my reasons:

1.-使用灯具仅用于测试所需的信息,但不会改变,例如,您需要一个用户进行每个测试,因此使用 base 夹具来创建用户。

1.- Use Fixtures only for information that is necessary for testing but is not going to change, for example, you need a user for every test you do so use a base fixture to create users.

2.-使用工厂创建您的对象,我个人喜欢 FactoryBoy < a>(这是来自FactoryGirl,这是一个红宝石图书馆)。我为我保存所有这些对象的每个应用程序创建一个名为factories.py的单独文件。这样我就可以将测试文件中的所有对象都保留下来,这样可以很容易地维护。关于这种方法的很酷的是,你创建一个基础对象,如果你想根据工厂的某些对象来测试别的东西,那么可以修改它。而且它不依赖于django,所以当我开始使用mongodb并且需要测试这些对象时,我迁移这些对象,一切顺利。现在看完工厂之后,通常会说为什么要用夹具。由于这些装置不应该改变工厂的所有额外的好东西都是无用的,而且django非常适合开箱即用。

2.- Use a factory to create your objects, I personally love FactoryBoy (this comes from FactoryGirl which is a ruby library). I create a separate file called factories.py for every app where I save all these objects. This way I keep off the test files all the objects I need which makes it a lot more readable and easy to maintain. The cool thing about this approach is that you create a base object that can be modified if you want to test something else based on some object from the factory. Also it doesn't depend on django so when I migrated these objects when I started using mongodb and needed to test them, everything was smooth. Now after reading about factories it's common to say "Why would I want to use fixtures then". Since these fixtures should never change all the extra goodies from factories are sort of useless and django supports fixtures very well out of the box.

3.-我 Mock 对外部服务的调用,因为这些调用使我的测试非常缓慢,它们依赖于与我的代码无关的事情。例如,如果我在测试中发短信,我会测试它正确的tweet,复制响应和模拟该对象,所以它每次返回确切的响应,而不做实际的调用。另外有时也很好测试出事情,嘲笑是非常棒的。

3.- I Mock calls to external services, because these calls make my tests very slow and they depend on things that have nothing to do with my code being right or wrong. for example, if I tweet within my test, I do test it to tweet rightly, copy the response and mock that object so it returns that exact response every time without doing the actual call. Also sometimes is good to test when things go wrong and mocking is great for that.

4.-我使用一个集成服务器( jenkins 是我的建议),每次我推到我的分期服务器运行测试,如果它们失败,它发送一封电子邮件。这是非常好的,因为我在很多事情发生在我最后一次变化中打破了别的东西,我忘了运行测试。它还为您提供其他好消息,如覆盖率报告, pylint / jslint / pep8 验证,并且存在大量可以插入的插件设置不同的统计信息。

4.- I use an integration server (jenkins is my recommendation here) which runs the tests every time I push to my staging server and if they fail it sends me an email. This is just great since it happens to me a lot that I break something else in my last change and I forgot to run the tests. It also gives you other goodies like a coverage report, pylint/jslint/pep8 verifications and there exists a lot of plugins where you can set different statistics.

关于您的测试前端的问题,django附带一些帮助函数以基本方式处理这个问题。

About your question for testing front end, django comes with some helper functions to handle this in a basic way.

这是什么我个人使用,你可以点击获取,发布,登录用户等,这对我来说足够了。我不喜欢使用像硒这样的完整的前端测试引擎,因为我觉得测试除了业务层之外的其他任何东西都是过分的。我相信有些会有所不同,它总是取决于你正在做什么。

This is what I personally use, you can fire gets, posts, login the user, etc. that's enough for me. I don't tend to use a complete front end testing engine like selenium since I feel it's an overkill to test anything else besides the business layer. I am sure some will differ and it always depends on what you are working on.

除了我的意见,django 1.4附带了一个非常方便的整合用于浏览器框架。

Besides my opinion, django 1.4 comes with a very handy integration for in-browser frameworks.

我将设置一个示例应用程序,我可以应用这种做法,以便更容易理解。我们创建一个非常基本的博客应用程序:

I'll set an example app where I can apply this practices so it is more understandable. Let's create a very basic blog app:

结构

blogger/
    __init__.py
    models.py
    fixtures/base.json
    factories.py
    tests.py

models.py

 from django.db import models

 class Blog(models.Model):
     user = models.ForeignKey(User)
     text = models.TextField()
     created_on = models.DateTimeField(default=datetime.now())

fixtures / base.json

[
{
    "pk": 1,
    "model": "auth.user",
    "fields": {
        "username": "fragilistic_test",
        "first_name": "demo",
        "last_name": "user",
        "is_active": true,
        "is_superuser": true,
        "is_staff": true,
        "last_login": "2011-08-16 15:59:56",
        "groups": [],
        "user_permissions": [],
        "password": "IAmCrypted!",
        "email": "test@email.com",
        "date_joined": "1923-08-16 13:26:03"
    }
}
]

factories.py

import factory
from blog.models import User, Blog

class BlogFactory(factory.Factory):
    FACTORY_FOR = Blog

    user__id = 1
    text = "My test text blog of fun"

tests.py

class BlogTest(TestCase):
    fixtures = ['base']  # loads fixture

    def setUp(self):
        self.blog = BlogFactory()
        self.blog2 = BlogFactory(text="Another test based on the last one")

    def test_blog_text(self):
        self.assertEqual(Blog.objects.filter(user__id=1).count(), 2)

    def test_post_blog(self):
        # Lets suppose we did some views
        self.client.login(username='user', password='IAmCrypted!')
        response = self.client.post('/blogs', {'text': "test text", user='1'})

        self.assertEqual(response.status, 200)
        self.assertEqual(Blog.objects.filter(text='test text').count(), 1)

    def test_mocker(self):
        # We will mock the datetime so the blog post was created on the date
        # we want it to
        mocker = Mock()
        co = mocker.replace('datetime.datetime')
        co.now()
        mocker.result(datetime.datetime(2012, 6, 12))

        with mocker:
            res = Blog.objects.create(user__id=1, text='test')

        self.assertEqual(res.created_on, datetime.datetime(2012, 6, 12))

    def tearDown(self):
        # Django takes care of this but to be strict I'll add it
        Blog.objects.all().delete()

N otice我为了这个例子而使用了一些特定的技术(没有经过测试btw)。

Notice I am using some specific technology for the sake of the example (which haven't been tested btw).

我必须坚持,这可能不是最好的标准实践(我怀疑它存在),但它对我来说很好。

I have to insist, this may not be the standard best practice (which I doubt it exists) but it is working pretty well for me.

这篇关于测试“不同层”的最佳做法是什么?在Django?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆