• frist Django app — 五、Test


    Test——很重要但是没有被重视起来的一个环节,至少是我自己,其实自己之前在做java web的时候就去尝试过怎么做REST接口的测试,一直没有找到一种合适方式,而且因为时间紧没有进一步深究,但是造成的后果每次做了修改之后都测试不充分,引起新的问题,所以这次对于python正好看看Django的单元测试。

    用的是单独的数据库,数据库是干净的(暂未有数据库,test所有操作都是从零开始),不会对正式的数据库造成影响

    Test Model

    到现在我们主要的业务逻辑代码在model和view里面,所以我们的测试也主要是针对model和view。在Django中我们的测试代码写在tests.py里面,这里我们先在models.py的Question类里面添加一个was_published_recently方法:

        def was_published_recently(self):
            now = timezone.now()
            return self.publ_date >= now - datetime.timedelta(days=1)

    接下来针对这个方法写单元测试

    class QuestionMethodTest(TestCase):
        def test_was_pblished_recently_with_future_question(self):
            time = timezone.now() + datetime.timedelta(days=30)
            future_question = Question(publ_date=time)
            self.assertEqual(future_question.was_published_recently(), False)
        def test_was_pblished_recently_with_old_question(self):
            time = timezone.now() - datetime.timedelta(days=30)
            future_question = Question(publ_date=time)
            self.assertEqual(future_question.was_published_recently(), False)
        def test_was_pblished_recently_with_recently_question(self):
            time = timezone.now() - datetime.timedelta(hours=1)
            future_question = Question(publ_date=time)
            self.assertEqual(future_question.was_published_recently(), True)

    这里先写了三个测试用例,分别测试

    • 时间大于当前时间的是否会被查到
    • 时间小于当前时间某些天的question是否会被查询到
    • 时间小于当前时间一天内(我们之前的“最近”的规则设置的就是一天)是否会被查询到

    我们再看看Django为我们的单元测试提供了怎样的环境。

    • 所有的测试继承自django.test.TestCase,TestCase提供了很多测试方法,比如:assertEqual,assertContains等
    • django会查找所有以test开头的方法(又一个约定大于配置)
    • 使用python manage.py test polls来运行我们的测试,可以只对某一个app运行测试
    • 每次测试进行的时候,django会创建新的数据库,测试完成之后会删除数据库,这样保证每次测试不会有污染数据

    我们在mysite目录里面运行测试

    python manage.py test polls

    可以看到输出

    Creating test database for alias 'default'...
    F..
    ======================================================================
    FAIL: test_was_pblished_recently_with_future_question (polls.tests.QuestionMethodTest)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/root/django/mysite/polls/tests.py", line 17, in test_was_pblished_recently_with_future_question
        self.assertEqual(future_question.was_published_recently(), False)
    AssertionError: True != False
    
    ----------------------------------------------------------------------
    Ran 3 tests in 0.001s
    
    FAILED (failures=1)
    Destroying test database for alias 'default'...

    可以看到总共三个测试,失败1个,查看失败信息发现返回的是true,和我们预期的不符,说明我们的was_published_recently函数的逻辑不正确,所有时间大于当前时间的应该不被查询出来,我们修正如下

        def was_published_recently(self):
            now = timezone.now()
            return now >= self.publ_date >= now - datetime.timedelta(days=1)

    再次运行就会发现三个均成功,结果是OK

    Creating test database for alias 'default'...
    ...
    ----------------------------------------------------------------------
    Ran 3 tests in 0.001s
    
    OK
    Destroying test database for alias 'default'...

    Test View

    view层会调用model层的代码实现业务逻辑,我们通过上面model的测试保证了model层的正确性,接下来可以借用django提供的环境测试我们的业务逻辑是否正确,编辑tests.py

    from django.test import TestCase
    import datetime
    from django.utils import timezone
    from polls.models import Question
    from django.core.urlresolvers import reverse
    
    # Create your tests here.
    
    def create_question(question_text, days):
        time = timezone.now() + datetime.timedelta(days=days)
        return Question.objects.create(question_text=question_text, publ_date=time)
    
    class QuestionMethodTest(TestCase):
        def test_was_pblished_recently_with_future_question(self):
            time = timezone.now() + datetime.timedelta(days=30)
            future_question = Question(publ_date=time)
            self.assertEqual(future_question.was_published_recently(), False)
        def test_was_pblished_recently_with_old_question(self):
            time = timezone.now() - datetime.timedelta(days=30)
            future_question = Question(publ_date=time)
            self.assertEqual(future_question.was_published_recently(), False)
        def test_was_pblished_recently_with_recently_question(self):
            time = timezone.now() - datetime.timedelta(hours=1)
            future_question = Question(publ_date=time)
            self.assertEqual(future_question.was_published_recently(), True)
    
    class QuestionViewTest(TestCase):
        def test_index_view_with_no_questions(self):
            response = self.client.get(reverse('polls:index'))
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'No polls are available')
            self.assertQuerysetEqual(response.context['latest_question_list'], [])
    
        def test_index_view_with_a_past_question(self):
            create_question('Past question.', -30)
            response = self.client.get(reverse('polls:index'))
            self.assertQuerysetEqual(response.context['latest_question_list'], ['<Question: Past question.>'])
        def test_index_view_with_a_future_question(self):
            create_question('Future question.', 30)
            response = self.client.get(reverse('polls:index'))
            self.assertContains(response, 'No polls are available')
            self.assertQuerysetEqual(response.context['latest_question_list'], [])
        def test_index_view_with_future_question_and_past_question(self):
            create_question('Past question.', -30)
            create_question('Future question.', 30)
            response = self.client.get(reverse('polls:index'))
            self.assertQuerysetEqual(response.context['latest_question_list'], ['<Question: Past question.>'])
        def test_index_view_with_two_past_question(self):
            create_question('Past question 1.', -30)
            create_question('Past question 2.', -5)
            response = self.client.get(reverse('polls:index'))
            self.assertQuerysetEqual(response.context['latest_question_list'], ['<Question: Past question 2.>', '<Question: Past question 1.>'])
    View Code

    django为我们的view层测试提供了更多的帮助

    • TestCase提供的包含一个client,表示一个客户端
    • 可以通过client调用get,post方法获取服务器的返回值response
    • 获取response的HttpCode,返回的context参数

    关于测试

    • more is better,test will look after themselves。测试用例越多,测试越全面,如果代码修改了,测试用例执行就会失败,就可以提醒我们去修改相应的测试
    • 一个单独的model或者view应该使用一个单独的test类
    • 每一种测试情况写单独的测试方法
    • 测试方法尽量描述它的功能(见文知意)

    完整代码

    http://pan.baidu.com/s/1geJ7DYj

  • 相关阅读:
    JavaScript 弹出层,背景变暗
    DataGridView常见用法和FAQ汇总
    将visual studio 2005 SP1补丁整合到安装文件
    非常经典的网络蜘蛛示例
    asp.net画曲线图(折线图)
    Asp.net中基类页的设计和使用
    使用 Visual C# .NET 向 Excel 工作簿传输数据
    CSS布局:让页脚始终保持底部的方法
    WinForm开发,窗体显示和窗体传值相关知识总结
    asp.net Urlrewriter在虚拟主机上的使用方法
  • 原文地址:https://www.cnblogs.com/sunshine-2015/p/5676873.html
Copyright © 2020-2023  润新知