How to unit test a project in Python's Django framework

Source: Internet
Author: User
Tags i18n
unit tests in Python





Let's review the unit test methods in Python.
Here is a simple example of a Python unit test:



If we develop a division function, some students may find it very simple, the code is this:


def division_funtion (x, y): 
 return x/y



But it is not right to write this way, some students can be tested under the code:


 

def division_funtion(x, y):

  return x / y

  

  

if __name__ == '__main__':

  print division_funtion(2, 1)

  print division_funtion(2, 4)

  print division_funtion(8, 3)

But this run to get the results, each time you have to calculate to check again, very inconvenient, Python has unittest module, can be easily tested, details can be the last link to the article, crossing Web documents detailed introduction.



The following is a simple example:


import unittest

  

  

def division_funtion(x, y):

  return x / y

  

  

class TestDivision(unittest.TestCase):

  def test_int(self):

    self.assertEqual(division_funtion(9, 3), 3)

  

  def test_int2(self):

    self.assertEqual(division_funtion(9, 4), 2.25)

  

  def test_float(self):

    self.assertEqual(division_funtion(4.2, 3), 1.4)

  

  

if __name__ == '__main__':

  unittest.main()


I have simply written three test examples (not necessarily comprehensive, just a demonstration, for example, without considering the divisor is a 0 case), after the run found:


F.F

======================================================================

FAIL: test_float (__main__.TestDivision)

----------------------------------------------------------------------

Traceback (most recent call last):

 File "/Users/tu/YunPan/mydivision.py", line 16, in test_float

  self.assertEqual(division_funtion(4.2, 3), 1.4)

AssertionError: 1.4000000000000001 != 1.4

  

======================================================================

FAIL: test_int2 (__main__.TestDivision)

----------------------------------------------------------------------

Traceback (most recent call last):

 File "/Users/tu/YunPan/1.py", line 13, in test_int2

  self.assertEqual(division_funtion(9, 4), 2.25)

AssertionError: 2 != 2.25

  

----------------------------------------------------------------------

Ran 3 tests in 0.001s

  

FAILED (failures=2)



Sweat! Found no, unexpectedly two have failed, the test found:



4.2 divided by 3 equals 1.4000000000000001 is not equal to expected value 1.4



9 divided by 4 equals 2, not equal to the desired 2.25



Here's what we're going to do to fix these problems and run the tests again until the error is run.



For example, according to the actual situation, suppose we only need to retain to 6 decimal places, we can change this:


def division_funtion (x, y):  return Round (float (x)/Y, 6)





Running again will not be the error:


...----------------------------------------------------------------------Ran 3 tests in 0.000s






Ok



Unit Tests in Django



Early unit Testing (unittest) is a good practice, and extreme situations even emphasize "test-first". Now that we have the first model class and the form class, it's time to start writing the test code.



Django supports Python's unit test and text test (Doc test), where we focus on unit testing. There is not much elaboration on the theory of unit testing, assuming you are familiar with the following concepts: test suite, test case, test/test action, test data, assert, and so on.



In unit testing, Django inherits Python's unittest.testcase to implement its own django.test.TestCase, and writing test cases usually starts here. The test code is usually located in the app's tests.py file (which can also be written in models.py, but I don't recommend it). In the Django-generated Depotapp, this file is already included and contains a sample of the test case:



depot/depotapp/tests.py


From django.test import Testcaseclass simpletest (TestCase):d ef test_basic_addition (self): "", Tests that 1 + 1 always equal s 2. "" " Self.assertequal (1 + 1, 2)


There are several ways you can run unit tests:


    • Python manage.py Test: Execute all test Cases
    • Python manage.py test app_name, execute all test cases for the app
    • Python manage.py test app_name.case_name: Executing the specified test case


The example provided above is executed in the third way, with the following results:


$ python manage.py test Depotapp. SimpleTest




Creating test database for alias 'default'...

.

----------------------------------------------------------------------

Ran 1 test in 0.012s

 

OK

Destroying test database for alias 'default'...


You may be primarily to the output information that includes operations to create and delete databases. To avoid the impact of the test data, the test process uses a separate database, and for details on how to specify the test database, consult the Django documentation. In our case, because of the SQLite database, Django will default to the in-memory database for testing.



Let's write the test case below. In "Agile Web development with Rails 4th", section 7.2, the final implementation of the Producttest code is as follows:


class ProductTest < ActiveSupport::TestCase

test "product attributes must not be empty"do

product = Product.new

assert product.invalid?

assert product.errors[:title].any?

assert product.errors[:description].any?

assert product.errors[:price].any?

assert product.errors[:image_url].any?

end

test "product price must be positive"do

product = Product.new(:title => "My Book Title",

:description => "yyy",

:image_url => "zzz.jpg")

product.price = -1

assert product.invalid?

assert_equal "must be greater than or equal to 0.01",

product.errors[:price].join('; ')

product.price = 0

assert product.invalid?

assert_equal "must be greater than or equal to 0.01",

product.errors[:price].join('; ')

product.price = 1

assert product.valid?

end

def new_product(image_url)

Product.new(:title => "My Book Title",

:description => "yyy",

:price => 1,

:image_url => image_url)

end

test "image url"do

ok = %w{ fred.gif fred.jpg fred.png FRED.JPG FRED.Jpg

http://a.b.c/x/y/z/fred.gif }

bad = %w{ fred.doc fred.gif/more fred.gif.more }

ok.eachdo |name|

assert new_product(name).valid?, "#{name} shouldn't be invalid"

end

bad.eachdo |name|

assert new_product(name).invalid?, "#{name} shouldn't be valid"

end

end

test "product is not valid without a unique title"do

product = Product.new(:title => products(:ruby).title,

:description => "yyy",

:price => 1,

:image_url => "fred.gif")

assert !product.save

assert_equal "has already been taken", product.errors[:title].join('; ')

end

test "product is not valid without a unique title - i18n"do

product = Product.new(:title => products(:ruby).title,

:description => "yyy",

:price => 1,

:image_url => "fred.gif")

assert !product.save

assert_equal I18n.translate('activerecord.errors.messages.taken'),

product.errors[:title].join('; ')

end

end





The content of the product test includes:



1.title,description,price,image_url cannot be empty;



2. Price must be greater than 0;



3. Image_url must end with jpg,png,jpg, and not sensitive to capitalization;



4. Titile must be unique;



Let's do these tests in Django. Because Productform contains model checksums and form validation rules, it is easy to implement these tests using Productform:



depot/depotapp/tests.py


#/usr/bin/python

#coding: utf8

"""

This file demonstrates writing tests using the unittest module. These will pass

when you run "manage.py test".

Replace this with more appropriate tests for your application.

"""

from django.test import TestCase

from forms import ProductForm

class SimpleTest(TestCase):

def test_basic_addition(self):

"""

Tests that 1 + 1 always equals 2.

"""

self.assertEqual(1 + 1, 2)

class ProductTest(TestCase):

def setUp(self):

self.product = {

'title':'My Book Title',

'description':'yyy',

'image_url':'http://google.com/logo.png',

'price':1

}

f = ProductForm(self.product)

f.save()

self.product['title'] = 'My Another Book Title'

#### title,description,price,image_url不能为空

def test_attrs_cannot_empty(self):

f = ProductForm({})

self.assertFalse(f.is_valid())

self.assertTrue(f['title'].errors)

self.assertTrue(f['description'].errors)

self.assertTrue(f['price'].errors)

self.assertTrue(f['image_url'].errors)

####  price必须大于零

def test_price_positive(self):

f = ProductForm(self.product)

self.assertTrue(f.is_valid())

self.product['price'] = 0

f = ProductForm(self.product)

self.assertFalse(f.is_valid())

self.product['price'] = -1

f = ProductForm(self.product)

self.assertFalse(f.is_valid())

self.product['price'] = 1

####  image_url必须以jpg,png,jpg结尾,并且对大小写不敏感;

def test_imgae_url_endwiths(self):

url_base = 'http://google.com/'

oks = ('fred.gif', 'fred.jpg', 'fred.png', 'FRED.JPG', 'FRED.Jpg')

bads = ('fred.doc', 'fred.gif/more', 'fred.gif.more')

for endwith in oks:

self.product['image_url'] = url_base+endwith

f = ProductForm(self.product)

self.assertTrue(f.is_valid(),msg='error when image_url endwith '+endwith)

for endwith in bads:

self.product['image_url'] = url_base+endwith

f = ProductForm(self.product)

self.assertFalse(f.is_valid(),msg='error when image_url endwith '+endwith)

self.product['image_url'] = 'http://google.com/logo.png'

###  titile必须唯一

def test_title_unique(self):

self.product['title'] = 'My Book Title'

f = ProductForm(self.product)

self.assertFalse(f.is_valid())

self.product['title'] = 'My Another Book Title'





Then run the Python manage.py test Depotapp. Producttest. As expected, the test did not pass:


Creating test database for alias 'default'...

.F..

======================================================================

FAIL: test_imgae_url_endwiths (depot.depotapp.tests.ProductTest)

----------------------------------------------------------------------

Traceback (most recent call last):

File "/Users/holbrook/Documents/Dropbox/depot/../depot/depotapp/tests.py", line 65, in test_imgae_url_endwiths

self.assertTrue(f.is_valid(),msg='error when image_url endwith '+endwith)

AssertionError: False is not True : error when image_url endwith FRED.JPG

 

----------------------------------------------------------------------

Ran 4 tests in 0.055s

 

FAILED (failures=1)

Destroying test database for alias 'default'...


Because we did not consider that the Image_url image extension might be capitalized. The relevant parts of modifying Productform are as follows:


def clean_image_url(self):

url = self.cleaned_data['image_url']

ifnot endsWith(url.lower(), '.jpg', '.png', '.gif'):

raise forms.ValidationError('图片格式必须为jpg、png或gif')

return url



Then run the test again:


$ python manage.py test Depotapp. Producttest




Creating test database for alias 'default'...

....

----------------------------------------------------------------------

Ran 4 tests in 0.060s

 

OK

Destroying test database for alias 'default'...



The test passed, and through the unit tests, we found and solved a bug.


  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.