1. 程式人生 > >django框架從零開始_010_自動化測試

django框架從零開始_010_自動化測試

參考:https://docs.djangoproject.com/en/1.9/intro/tutorial05/

為什麼需要自動化測試?因為這可以在你的程式修改的時候告訴你是否對原先功能產生影響。不同於之前的手動測試,自動化測試是你預先建立一部分例子,在你修改程式碼後執行這些例子然後檢查結果是否仍是你需要的。這樣就可以省去每一次手工測試的時間。在實際生產中,這種自動化測試是必不可少的。關於自動化測試的重要性這裡就不再贅述了。

自動化測試的策略有很多。有些程式設計師願意遵從一種“test-driven”的方法,即在寫程式之前,先定義好一些測試用例,然後實現你的程式碼邏輯去解決他們。這似乎有些順序上的不對勁,但是實際上這和使用者的使用方式是相同的:描述一個問題,然後解決他。然而更多的新人是先寫好一部分程式碼,然後覺得他們應該寫一些測試用例。不管怎樣,現在開始做測試都不算晚。

有時很難決定要從哪裡開始進行測試。如果你已經有了幾千行程式碼,那測試的確是個費勁的活兒。在這種情況下,你的測試可以新增在下一次你的程式碼改動的時候,比如新增新功能或者fix bugs。對於我們這個小程式,讓我們現在就開始建立第一個測試。

正好,我們之前的程式碼存在一些小bug。比如,在Question.was_published_recently()方法中,如果question是新建於今天的話會返回True,但是如果這個時間是在未來的話也會返回True(雖然實際不該發生)。我們可以通過控制檯來確認一下:

>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> # create a Question instance with pub_date 30 days in the future
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> # was it published recently?
>>> future_question.was_published_recently()
True

這應該是錯誤的,讓我們來建立測試用例來顯露出這個bug。

tests.py是一個方便的建立apps測試用例的地方,整個自動測試系統會自動尋找所有的以test開頭的方法來確定測試用例。

更新tests.py:

from django.test import TestCase

import datetime
from django.utils import timezome
from .models import Question

# Create your tests here.

class QuestionMethodTests(TestCase):
    def test_was_published_recently_with_future_question(self):
        '''
        was_published_recently() should return False for questions whose pub_date is in the future.
        '''
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        
        self.assertEqual(future_question.was_published_recently(), False)

在這裡,我們建立了django.test.TestCase的子類,在其中建立了一個測試方法新建了未來時間的question,並檢查他的was_published_recently()方法應該返回False。

OK,我們來執行測試。執行方法為在cmd下:

$ python manage.py test polls
我們來看一下結果:


額,看來django使用者沒有建立資料庫的許可權。給django使用者建立資料庫的許可權之後我們再次執行測試:


可以看到,測試用例丟擲了錯誤,並詳細指出了哪一行、哪個方法出現了錯誤。

好,下面我們來修復這個錯誤:

polls/models.py:

class Question(models.Model):
    ......
    def was_published_recently(self):
        return timezone.now() > self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    ......

再次測試:

很好!而且即使專案再複雜,我們也不用擔心這個錯誤再次出現了。

下面我們可以繼續新增更多的測試用例:

from django.test import TestCase

import datetime
from django.utils import timezone
from .models import Question

# Create your tests here.

class QuestionMethodTests(TestCase):
    def test_was_published_recently_with_future_question(self):
        '''
        was_published_recently() should return False for questions whose pub_date is in the future.
        '''
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        
        self.assertEqual(future_question.was_published_recently(), False)
        
    def test_was_published_recently_with_old_question(self):
        '''
        was_published_recently() should return False for questions whose pub_date is older than 1 day.
        '''
        time = timezone.now() - datetime.timedelta(days=3)
        future_question = Question(pub_date=time)
        self.assertEqual(future_question.was_published_recently(), False)
        
    def test_was_published_recently_with_recent_question(self):
        '''
        was_published_recently() should return False for questions whose pub_date is older than 1 day.
        '''
        time = timezone.now() - datetime.timedelta(hours=3)
        future_question = Question(pub_date=time)
        self.assertEqual(future_question.was_published_recently(), True)
        

顯然,這些結果都是對的。


好了,有了這三個例子,我們可以保證,這個方法對以前、現在、將來的question都會正常工作了。