18. Проект растет - тестов
становится много
...
./tests/
./tests/test_add.py
./tests/test_sub.py
./tests/test_div.py
./tests/test_mul.py
./tests/test_pi.py
19. Nose - запускалка тестов
Устанавливаем nose
$ pip install nose
Запускаем тесты
$ nosetests
..
--------------------------------------------
Ran 100500 tests in 0.219s
OK
23. Запуск тестов в Django
Запуск всех тестов в папке ./blog
$ manage.py test ./blog --settings project.
testing_settings
Запуск тестов в одном файле
$ manage.py test ./blog/test/test_forms.py --settings
project.testing_settings
24. Запуск тестов только для одного класса
$ manage.py test ./blog/test/test_forms.py:PostFormTest
--settings project.testing_settings
Запуск только одного теста
$ manage.py test ./blog/test/test_forms.py:PostFormTest.
test_post_from_submit --settings project.testing_settings
26. Тест view
from django.test import TestCase, Client
class HomePageTest(TestCase):
def test_homepage_is_available(self):
c = Client()
response = c.get('/')
self.assertEquals(response.status_code, 200)
27. class HomePageTest(TestCase):
def setUp(self):
self.posts = [ ]
for i in range(20):
post = Post.objects.create(
title = "Hello %d" % i,
)
self.posts.append(post)
def test_homepage_contains_posts(self):
pass
28. class HomePageTest(TestCase):
def setUp(self):
self.posts = [ ]
for i in range(20):
post = Post.objects.create(
title = "Hello %d" % i,
)
self.posts.append(post)
def test_homepage_contains_posts(self):
c = Client()
response = c.get('/')
self.assertEquals(response.status_code, 200)
self.assertIn(self.posts[-1].title, response.content)
self.assertIn(self.posts[-2].title, response.content)
31. from django.db import models
class Post(models.Model):
picture = models.ImageField(
upload_to='posts', blank=True, null=True)
title = models.CharField(max_length=255)
body = models.CharField(max_length=255)
class Meta:
ordering = ['-id']
32. Отправка формы
class PostFormTest(TestCase):
def test_post_from_submit(self):
c = Client()
params = {'title':'Hello Pycon'}
response = c.post('/posts/add/', params)
self.assertEquals(response.status_code, 302)
post = Post.objects.get(title=params['title'])
40. Прочее в Django
- Middleware
- Template tags, filters
- Context processors
- тестируются модульными тестами как
простые функции, аналогично с
примером 1+1 = 2
41. Особенности тестов view в Django
----------------------------
middleware
-----------------------------
context processors
-----------------------------
template
-----------------------------
view
-----------------------------
models
-----------------------------
network
42. Flexmock
- Заменять части объектов и классов
- Заменять функции, в том числе
встроенные
- Создавать объекты заглушки
- Проверять ожидания (сколько раз
вызван метод, с какими аргументами)
47. Есть требования ...
def get_url_content(url):
# ToDo
# Вернуть контент страницы
# или None, в случае ошибки
pass
48. Как написать тест?
def test_get_url_content(self):
url = 'http://example.com'
text = get_url_content(url)
self.assertEquals(text, ???)
49. Тестирование реализации
Пишем тест имея представление о внутренностях
def get_url_content(url):
try:
response = urllib.urlopen(url)
content = response.read()
response.close()
except IOError:
return None
return content
Неверно с точки зрения теории,
удобно на практике
50. Тест для случая нормального
выполнения
def test_get_url_content(self):
url = 'http://example.com'
response = StringIO("<html>")
(flexmock(urllib)
.should_receive('urlopen')
.with_args(url)
.and_return(response)
.once())
text = get_url_content(url)
self.assertEquals(text, "<html>")
51. Тест в случае ошибки сети
def test_get_url_content_on_ioerror(self):
url = 'http://example.com'
(flexmock(urllib)
.should_receive('urlopen')
.with_args(url)
.and_raise(IOError("test exception"))
.once())
text = get_url_content(url)
self.assertEquals(text, None)