测试驱动开发是python web开发里面一个很重要的角色!使用测试来推动开发的进程,通过测试用例的编写,对需求功能分解,使用过程和接口都进行了设计,而tdd里面的测试代码用例是对自己的代码最好的解释。测试驱动开发最重要的功能还在于保障代码的正确性,能够迅速发现、定位bug。而迅速发现、定位bug
下面简单讲下python里面用到的三种单元测试框架
- unitest
- django.test
- rest-framework.test
- 如何编写单元测试
1. unitest.TestCase 系统提供的测试工具
unittest模块提供了一组丰富的工具来构建和运行测试。下面演示了这些工具的一小部分足以满足大多数用户的需求。
下面是一个测试三种字符串方法的简短脚本:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
unittest.main()
testcase是由子类化unittest.testcase创建的。这三个单独的测试是用名字以字母测试开始的方法定义的。这种命名约定通知测试运行者关于哪些方法表示测试。每个测试的关键是对断言()的调用,以检查预期的结果;断言()或断言错误()来验证一个条件;或者断言()来验证一个特定的异常是否被提高。这些方法被用来代替assert语句,这样测试运行者就可以累积所有的测试结果并生成报告。
也可以使用以下两句话来代替上面代码的最后两行
suite = unittest.TestLoader().loadTestsFromTestCase(TestStringMethods)
unittest.TextTestRunner(verbosity=2).run(suite)
2. django.testTestCase django框架提供的测试框架
2.1 如何编写django的测试框架
django.test依赖于python的unitest框架,testcase的测试方法依赖于类的方法定义测试
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
Animal.objects.create(name="lion", sound="roar")
Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
cat = Animal.objects.get(name="cat")
self.assertEqual(lion.speak(), 'The lion says "roar"')
self.assertEqual(cat.speak(), 'The cat says "meow"')
2.2 如何运行django的测试框架
当您运行测试时,测试实用程序的默认行为是在任何以test开头的文件中找到所有的测试用例(即unittest.testcase的子类),自动地从这些测试用例中构建一个测试套件,并运行该套件。您可以通过向。/manage提供任意数量的“测试标签”来指定要运行的特定测试。py测试。每个测试标签都可以是一个完整的Python点路径到一个包、模块、TestCase子类或测试方法。
# Run all the tests in the animals.tests module
$ ./manage.py test animals.tests
# Run all the tests found within the 'animals' package
$ ./manage.py test animals
# Run just one test case
$ ./manage.py test animals.tests.AnimalTestCase
# Run just one test method
$ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak
如果您在测试运行时按Ctrl-C,那么测试运行程序将等待当前运行的测试完成,然后优雅地退出。在一个优雅的退出过程中,测试运行程序将输出任何测试失败的详细信息,报告运行了多少测试以及遇到了多少错误和故障,并像往常一样销毁任何测试数据库。因此,如果您忘记传递-failfast选项,那么按Ctrl-C是非常有用的,注意一些测试出乎意料地失败,并且希望在不等待完整测试运行完成的情况下获得失败的详细信息。
3. rest-framework.test基于restframework的api测试
rft的创建测试请求和django的一致,所以其也可以实现self.get|post等系列请求
class ProductViewTest(TestCassMixin, APITestCase):
base_url = '/store/product'
model = Product
serializer_class = ProductSerializer
def test_list_filter(self):
"""列表筛选功能"""
url = f"{self.base_url}/"
query_keys = ("brand", "type")
foreign_keys = ("brand", )
for key in query_keys:
if key in foreign_keys:
val = getattr(self.product, key + "_id")
else:
val = getattr(self.product, key)
# 查询条件匹配,返回数据 > 0
response = self.client.get(url, data={key: val})
self.assertEqual(response.status_code, 200) # 接口响应正确
self.assertGreater(response.data['count'], 0)
# 查询条件不匹配,返回数据 = 0
response = self.client.get(url, data={key: val + 1})
self.assertEqual(response.status_code, 200) # 接口响应正确
self.assertEqual(response.data['count'], 0)
更多测试方式:http://www.django-rest-framework.org/api-guide/testing/
4. 如何编写单元测试
4.1 这个例子是测试myapp.models 中的 Animal 类相关的方法功能。
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
Animal.objects.create(name="lion", sound="roar")
Animal.objects.create(name="cat", sound="meow")
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
cat = Animal.objects.get(name="cat")
self.assertEqual(lion.speak(), 'The lion says "roar"')
self.assertEqual(cat.speak(), 'The cat says "meow"')
4.2 用代码访问网址的方法:
>>> from django.test import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
'
我们可以用 django.test.Client 的实例来实现 get 或 post 内容,检查一个网址返回的网页源代码。
默认情况下CSRF检查是被禁用的,如果测试需要,可以用下面的方法:
>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)
使用 csrf_client 这个实例进行请求即可。
指定浏览USER-AGENT:
>>> c = Client(HTTP_USER_AGENT='Mozilla/5.0')
模拟post上传附件:
from django.test import Client
c = Client()
with open('wishlist.doc') as fp:
c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})
测试网页返回状态:
from django.test import TestCase
class SimpleTest(TestCase):
def test_details(self):
response = self.client.get('/customer/details/')
self.assertEqual(response.status_code, 200)
def test_index(self):
response = self.client.get('/customer/index/')
self.assertEqual(response.status_code, 200)
我们用 self.client 即可,不用 client = Client() 这样实例化,更方便,我们还可以继承 Client,添加一些其它方法:
from django.test import TestCase, Client
class MyTestClient(Client):
# Specialized methods for your environment
...
class MyTest(TestCase):
client_class = MyTestClient
def test_my_stuff(self):
# Here self.client is an instance of MyTestClient...
call_some_test_code()
定制 self.client 的方法:
from django.test import Client, TestCase
class MyAppTests(TestCase):
def setUp(self):
super(MyAppTests, self).setUp()
self.client = Client(enforce_csrf_checks=True)
def test_home(self):
response = self.client.get('/')
self.assertEqual(response.status_code, 200)