笨鸟编程-零基础入门Pyhton教程

 找回密码
 立即注册

编写你的第一个 Django 程序 第5部分

发布者: 三寸日光



Basic testing strategies

There are many ways to approach writing tests.

Some programmers follow a discipline called “test-driven development”; they actually write their tests before they write their code. This might seem counter-intuitive, but in fact it’s similar to what most people will often do anyway: they describe a problem, then create some code to solve it. Test-driven development simply formalizes the problem in a Python test case.

More often, a newcomer to testing will create some code and later decide that it should have some tests. Perhaps it would have been better to write some tests earlier, but it’s never too late to get started.

Sometimes it’s difficult to figure out where to get started with writing tests. If you have written several thousand lines of Python, choosing something to test might not be easy. In such a case, it’s fruitful to write your first test the next time you make a change, either when you add a new feature or fix a bug.

So let’s do that right away.

Writing our first test

We identify a bug

Fortunately, there’s a little bug in the polls application for us to fix right away: the Poll.was_published_recently() method returns True if the Poll was published within the last day (which is correct) but also if the Poll‘s pub_date field is in the future (which certainly isn’t).

You can see this in the Admin; create a poll whose date lies in the future; you’ll see that the Poll change list claims it was published recently.

You can also see this using the shell:

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

Since things in the future are not ‘recent’, this is clearly wrong.

Create a test to expose the bug

What we’ve just done in the shell to test for the problem is exactly what we can do in an automated test, so let’s turn that into an automated test.

The best place for an application’s tests is in the application’s tests.py file - the testing system will look there for tests automatically.

Put the following in the tests.py file in the polls application (you’ll notice tests.py contains some dummy tests, you can remove those):

import datetime

from django.utils import timezone
from django.test import TestCase

from polls.models import Poll

class PollMethodTests(TestCase):

    def test_was_published_recently_with_future_poll(self):
        """
        was_published_recently() should return False for polls whose
        pub_date is in the future
        """
        future_poll = Poll(pub_date=timezone.now() + datetime.timedelta(days=30))
        self.assertEqual(future_poll.was_published_recently(), False)

What we have done here is created a django.test.TestCase subclass with a method that creates a Poll instance with a pub_date in the future. We then check the output of was_published_recently() - which ought to be False.

Running tests

In the terminal, we can run our test:

python manage.py test polls

and you’ll see something like:

Creating test database for alias 'default'...
F
======================================================================
FAIL: test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/path/to/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_poll
    self.assertEqual(future_poll.was_published_recently(), False)
AssertionError: True != False

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)
Destroying test database for alias 'default'...

What happened is this:

  • python manage.py test polls looked for tests in the polls application
  • it found a subclass of the django.test.TestCase class
  • it created a special database for the purpose of testing
  • it looked for test methods - ones whose names begin with test
  • in test_was_published_recently_with_future_poll it created a Poll instance whose pub_date field is 30 days in the future
  • ... and using the assertEqual() method, it discovered that its was_published_recently() returns True, though we wanted it to return False

The test informs us which test failed and even the line on which the failure occurred.

Fixing the bug

We already know what the problem is: Poll.was_published_recently() should return False if its pub_date is in the future. Amend the method in models.py, so that it will only return True if the date is also in the past:

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

and run the test again:

Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
Destroying test database for alias 'default'...

After identifying a bug, we wrote a test that exposes it and corrected the bug in the code so our test passes.

Many other things might go wrong with our application in the future, but we can be sure that we won’t inadvertently reintroduce this bug, because simply running the test will warn us immediately. We can consider this little portion of the application pinned down safely forever.


Archiver|手机版|笨鸟自学网 ( 粤ICP备20019910号 )

GMT+8, 2024-9-8 11:18 , Processed in 0.026182 second(s), 17 queries .

© 2001-2020

返回顶部