Python單元測試
是用來對一個模塊、一個函數或者一個類進行正確性檢驗的測試工作。
在Python中unittest是它內置的單元測試框架,單元測試與功能測試都是日常開發中必不可少的部分。
比如對函數abs(),我們可以編寫出一下幾個測試用例:
- 輸入正數,比如1,1.2,0.99,我們期待返回值與輸入相同
- 輸入負數,比如-1,-1.2,-0.99,我們期待返回值與輸入值相反
- 輸入0,我們期待返回0
- 輸入非數值類型,比如None,[],{},我們期待拋出TypeError
把上面的測試用例放到一個測試模塊里,就是一個完整的單元測試。
一個簡單的測試用例
定義一個類,簡單的實現add、sub兩方法,並對其進行單元測試
待測試文件m1.py
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 class MyClass(object): 6 def __init__(self, x, y): 7 self.x = int(x) 8 self.y = int(y) 9 10 def add(self): 11 return self.x + self.y 12 13 def sub(self): 14 return self.x - self.y
在m1.py同級目錄下創建test.py測試文件,使用unittest單元測試框架對MyClass的方法進行測試
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import unittest 5 from m1 import MyClass 6 7 8 class MyclassTest(unittest.TestCase): 9 def setUp(self): 10 self.calc = MyClass(7, 5) 11 12 def tearDown(self): 13 pass 14 15 def test_add(self): 16 ret = self.calc.add() 17 self.assertEqual(ret, 12) 18 19 def test_sub(self): 20 ret = self.calc.sub() 21 self.assertEqual(ret, 2) 22 23 24 # if __name__ == '__main__': 25 # suite = unittest.TestSuite() 26 # suite.addTest(MyclassTest('test_add')) 27 # suite.addTest(MyclassTest('test_sub')) 28 # 29 # runner = unittest.TextTestRunner() 30 # runner.run(suite) 31 32 if __name__ == '__main__': 33 unittest.main()
運行測試
1 python -m unittest test 2 .. 3 ---------------------------------------------------------------------- 4 Ran 2 tests in 0.000s 5 6 OK
總結:
編寫單元測試時,我們需要編寫一個測試類,從unittest.TestCase繼承,unittest.TestCase提供了很多內置的條件判斷,我們只需要調用這些方法就可以斷言輸出是否是我們所期望的。最常用的斷言就是assertEqual()方法
運行單元測試:
1 一旦編寫好單元測試,我們就可以運行單元測試。最簡單的運行方式是在test.py的最后加上兩行代碼: 2 if __name__ == '__main__': 3 unittest.main() 4 這樣就可以把test.py當做正常的python腳本運行: 5 $ python test.py 6 另一種方法是在命令行通過參數-m unittest直接運行單元測試: 7 $ python -m unittest test
unittest框架小知識點梳理
1. test fixture:是初始化和清理測試數據及環境,通過重寫TestCase的setUp()和tearDown()方法實現
兩方法使用:設想你的測試需要啟動一個數據庫,這時,就可以在setUp()方法中連接數據庫,在tearDown()方法中關閉數據庫,這樣,不必在每個測試方法中重復相同的代碼:
1 class MyclassTest(unittest.TestCase): 2 3 def setUp(self): 4 print('setUp...') 5 6 def tearDown(self): 7 print('tearDown...')
2.test case:是測試用例
3.test suite:是測試用例的集合,通過addTest加載TestCase到TestSuite中,返回一個TestSuite實例
4.test runner:是運行測試用例並返回結果,通過TextTestRunner類提供的run()方法來執行test suite或test case
注意:
單元測試通過了並不意味着程序就沒有bug了,但是不通過程序肯定有bug
Django中的單元測試
在創建app的時候,在app目錄下自動生成tests.py文件
Model部分單元測試用例
1 from django.db import models 2 3 # Create your models here. 4 5 6 class Book(models.Model): 7 title = models.CharField(max_length=32) 8 price = models.DecimalField(max_digits=10, decimal_places=2)
測試用例代碼
1 from django.test import TestCase 2 from app01.models import Book 3 # Create your tests here. 4 5 6 class BookModelTest(TestCase): 7 def setUp(self): 8 Book.objects.create(title='斗破蒼穹', price=10.99) 9 10 def test_book_model(self): 11 from decimal import Decimal 12 result = Book.objects.get(title='斗破蒼穹') 13 self.assertEqual(result.price, Decimal('10.99'))
運行測試在項目目錄下運行:
1 python manage.py test 2 Creating test database for alias 'default'... 3 System check identified no issues (0 silenced). 4 . 5 ---------------------------------------------------------------------- 6 Ran 1 test in 0.002s 7 8 OK 9 Destroying test database for alias 'default'...
視圖部分單元測試用例
1 from django.shortcuts import render 2 3 # Create your views here. 4 5 6 def index(request): 7 return render(request, 'index.html')
在app01/tests.py文件中添加測試用例代碼:
1 class IndexPageTest(TestCase): 2 """測試index頁面""" 3 def test_index_page_renders_index_template(self): 4 """測試index視圖""" 5 response = self.client.get('/index/') 6 self.assertEqual(response.status_code, 200) # 判斷狀態碼 7 self.assertTemplateUsed(response, 'index.html') # 判斷渲染的模板是否正確
運行單元測試:
1 python manage.py test 2 Creating test database for alias 'default'... 3 System check identified no issues (0 silenced). 4 .. 5 ---------------------------------------------------------------------- 6 Ran 2 tests in 0.044s 7 8 OK 9 Destroying test database for alias 'default'...