SlideShare a Scribd company logo
Тестирование
      и Django
      Илья Барышев
       @coagulant


 Moscow Django Meetup №6
Защита от
регрессий
Быстрые
изменения
  в коде
Меняет подход к
написанию кода
Пойдёт на пользу
 вашему проекту
Модульное
тестирование
 	
  	
  	
  def	
  test_vin_is_valid(self):
	
  	
  	
  	
  	
  	
  	
  	
  valid_vins	
  =	
  ('2G1FK1EJ7B9141175',
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  '11111111111111111',)
	
  	
  	
  	
  	
  	
  	
  	
  for	
  valid_vin	
  in	
  valid_vins:
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self.assertEqual(vin_validator(valid_vin),	
  None)


	
  	
  	
  	
  def	
  test_vin_is_invalid(self):
	
  	
  	
  	
  	
  	
  	
  	
  invalid_vins	
  =	
  ('abc',	
  u'M05C0WDJAN60M33TUP6',)
	
  	
  	
  	
  	
  	
  	
  	
  for	
  invalid_vin	
  in	
  invalid_vins:
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  self.assertRaises(ValidationError,	
  
                                                   	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  vin_validator,	
  invalid_vin)
Unittest

Модели      Контекст-процессоры
Формы       Middleware
Views?      Template tags, filters
Тестируйте поведение
     А не имплементацию
Функциональное
 тестирование
django.test.client.Client
def	
  testPostAsAuthenticatedUser(self):
	
  	
  	
  	
  data	
  =	
  self.getValidData(Article.objects.get(pk=1))
	
  	
  	
  	
  self.client.login(username="normaluser",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  password="normaluser")
	
  	
  	
  	
  self.response	
  =	
  self.client.post("/post/",	
  data)
	
  	
  	
  	
  
	
  	
  	
  	
  self.assertEqual(self.response.status_code,	
  302)
	
  	
  	
  	
  self.assertEqual(Comment.objects.count(),	
  1)
django.test.сlient.RequestFactory
def	
  test_post_ok(self):
	
  	
  	
  	
  request	
  =	
  RequestFactory().post(reverse('ch_location'),
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  {'location_id':	
  77})
	
  	
  	
  	
  request.cookies	
  =	
  {}

	
  	
  	
  	
  response	
  =	
  change_location(request)

	
  	
  	
  	
  self.assertEqual(response.cookies['LOCATION'].value,	
  '77')
	
  	
  	
  	
  self.assertEqual(response.status_code,	
  302)
Smoke Testing
def	
  test_password_recovery_smoke(self):
         	
  	
  	
  	
  """
         	
  	
  	
  	
  Урлы	
  восстановления	
  пароля.
         	
  	
  	
  	
  Логика	
  уже	
  протестирована	
  в	
  django-­‐password-­‐reset
         	
  	
  	
  	
  """
         	
  	
  	
  	
  response_recover	
  =	
  self.client.get(reverse('pass_recover'))
         	
  	
  	
  	
  
         	
  	
  	
  	
  self.assertEqual(response_recover.status_code,	
  200)

	
  	
  	
  	
  	
  	
  	
  	
  self.assertContains(response_recover,
	
  	
  	
  	
  	
  	
  	
  	
  self.assertTemplateUsed(response_recover,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  u'Восстановление	
  пароля')
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'password_reset/recovery_form.html')
Как мы тестируем
Continious
Integration
Покрытие важно
  Но не делайте из него фетиш
mock
http://www.voidspace.org.uk/python/mock/
>>>	
  real	
  =	
  SomeClass()
>>>	
  my_mock	
  =	
  MagicMock(name='method')
>>>	
  real.method	
  =	
  my_mock
>>>	
  real.method(3,	
  4,	
  5,	
  key='value')
>>>	
  my_mock.called
True
>>>	
  my_mock.call_count
1
>>>	
  mock.method.assert_called_with(3,	
  4,	
  5)
Traceback	
  (most	
  recent	
  call	
  last):
	
  	
  ...
AssertionError:	
  Expected	
  call:	
  method(3,	
  4,	
  5)
Actual	
  call:	
  method(3,	
  4,	
  5,	
  key='value')
@patch('twitter.Api')
def	
  test_twitter_tag_simple_mock(self,	
  ApiMock):
	
  	
  	
  	
  api_instance	
  =	
  ApiMock.return_value
	
  	
  	
  	
  api_instance.GetUserTimeline.return_value	
  =	
  SOME_JSON

	
  	
  	
  	
  output,	
  context	
  =	
  render_template(
                   """{%	
  load	
  twitter_tag	
  %}
                     	
  {%	
  get_tweets	
  for	
  "jresig"	
  as	
  tweets	
  %}""")

	
  	
  	
  	
  api_instance.GetUserTimeline.assert_called_with(
	
  	
  	
  	
  	
  	
  	
  	
  screen_name='jresig',	
  
	
  	
  	
  	
  	
  	
  	
  	
  include_rts=True,	
  
	
  	
  	
  	
  	
  	
  	
  	
  include_entities=True)
from	
  mock	
  import	
  patch
from	
  django.conf	
  import	
  settings

@patch.multiple(settings,	
  APPEND_SLASH=True,
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  MIDDLEWARE_CLASSES=(common_middleware,))
def	
  test_flatpage_doesnt_require_trailing_slash(self):
	
  	
  	
  	
  form	
  =	
  FlatpageForm(data=dict(url='/no_trailing_slash',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  **self.form_data))
	
  	
  	
  	
  self.assertTrue(form.is_valid())
from	
  django.test.utils	
  import	
  override_settings

@override_settings(
	
  	
  	
  	
  APPEND_SLASH=False,	
  
	
  	
  	
  	
  MIDDLEWARE_CLASSES=(common_middleware,)
)
def	
  test_flatpage_doesnt_require_trailing_slash(self):
	
  	
  	
  	
  form	
  =	
  FlatpageForm(data=dict(url='/no_trailing_slash',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  **self.form_data))
	
  	
  	
  	
  self.assertTrue(form.is_valid())
Фикстуры
[
    {
         "model": "docs.documentrelease",
         "pk": 1,
         "fields": {
           "lang": "en",
           "version": "dev",
           "scm": "svn",
           "scm_url": "http://code.djangoproject.com/svn/django/trunk/docs",
           "is_default": false
         }
    },
    {
         "model": "docs.documentrelease",             Обычный тест с
         "pk": 2,                                     фикстурами
         "fields": {
           "lang": "en",
           "version": "1.0",
           "scm": "svn",
           "scm_url": "http://code.djangoproject.com/svn/django/branches/releases/1.0.X/docs",
           "is_default": false
         }
    },
    {
         "model": "docs.documentrelease",
         "pk": 3,
         "fields": {
           "lang": "en",
           "version": "1.1",
           "scm": "svn",
           "scm_url": "http://code.djangoproject.com/svn/django/branches/releases/1.1.X/docs",
           "is_default": false
django-­‐any
                            https://github.com/kmmbvnr/django-­‐any


from	
  django_any	
  import	
  any_model

class	
  TestMyShop(TestCase):
	
  	
  	
  	
  def	
  test_order_updates_user_account(self):
	
  	
  	
  	
  	
  	
  	
  	
  account	
  =	
  any_model(Account,	
  amount=25,	
  
                                          	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  user__is_active=True)
	
  	
  	
  	
  	
  	
  	
  	
  order	
  =	
  any_model(Order,	
  user=account.user,	
  
                                          	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  amount=10)
	
  	
  	
  	
  	
  	
  	
  	
  order.proceed()

	
  	
  	
  	
  	
  	
  	
  	
  account	
  =	
  Account.objects.get(pk=account.pk)
	
  	
  	
  	
  	
  	
  	
  	
  self.assertEquals(15,	
  account.amount)
factory_boy
https://github.com/dnerdy/factory_boy
import	
  factory
from	
  models	
  import	
  MyUser

class	
  UserFactory(factory.Factory):
	
  	
  	
  	
  FACTORY_FOR	
  =	
  MyUser
	
  	
  	
  	
  first_name	
  =	
  'John'
	
  	
  	
  	
  last_name	
  =	
  'Doe'
	
  	
  	
  	
  admin	
  =	
  False
#	
  Инстанс,	
  сохранённый	
  в	
  базу
user	
  =	
  UserFactory.create()

#	
  Экземпляр	
  User,	
  не	
  сохранённый	
  в	
  базу
user	
  =	
  UserFactory.build()

#	
  Создаём	
  инстанс	
  с	
  конкретыми	
  значениями
user	
  =	
  UserFactory.create(name=u'Василий',	
  age=25)
class	
  UserFactory(factory.Factory):
	
  	
  	
  	
  first_name	
  =	
  'Vasily'
	
  	
  	
  	
  last_name	
  =	
  'Pupkin'
	
  	
  	
  	
  email	
  =	
  factory.LazyAttribute(
                     lambda	
  u:	
  '{0}.{1}@example.com'.format(
                     u.first_name,	
  u.last_name).lower())


>>>	
  UserFactory().email
'vasily.pupkin@example.com'
class	
  UserWithEmailFactory(UserFactory):
	
  	
  	
  	
  email	
  =	
  factory.Sequence(
                   lambda	
  n:	
  'person{0}@example.com'.format(n))


>>>	
  UserFactory().email
'person0@example.com'

>>>	
  UserFactory().email	
  	
  
'person1@example.com'
Django test runner
     SUCKS
INSTALLED_APPS	
  =	
  (
	
  	
  	
  	
  ...

	
  	
  	
  	
  #3rd-­‐party	
  apps
	
  	
  	
  	
  'south',
	
  	
  	
  	
  'sorl.thumbnail',
	
  	
  	
  	
  'pytils',
	
  	
  	
  	
  'pymorphy',	
  	
  	
  	
  	
  
	
  	
  	
  	
  'compressor',
                                                  Несколько сотен
	
  	
  	
  	
  'django_nose',                        тестов
	
  	
  	
  	
  'django_geoip',
	
  	
  	
  	
  'mptt',
	
  	
  	
  	
  'widget_tweaks',
	
  	
  	
  	
  'guardian',
	
  	
  	
  	
  
	
  	
  	
  	
  ...
/tests                               #	
  -­‐*-­‐	
  coding:	
  utf-­‐8	
  -­‐*-­‐
	
  	
  	
  	
  __init__.py
                test_archive.py      from	
  test_archive	
  import	
  *
	
  	
  	
  	
  test_blog_model.py   from	
  test_blog_model	
  import	
  *
	
  	
  	
  	
  test_modified.py     from	
  test_modified	
  import	
  *
	
  	
  	
  	
  test_post_model.py   from	
  test_post_model	
  import	
  *
	
  	
  	
  	
  test_redactor.py     from	
  test_redactor	
  import	
  *
	
  	
  	
  	
  test_views.py        from	
  test_views	
  import	
  *
	
  	
  	
  	
  test_cross_post.py   from	
  test_cross_post	
  import	
  *
django-­‐nose




          https://github.com/jbalogh/django-­‐nose
$	
  pip	
  install	
  django-­‐nose


  #	
  settings.py	
  
  INSTALLED_APPS	
  =	
  (
  	
  	
  	
  	
  ...
  	
  	
  	
  	
  'django_nose',
  	
  	
  	
  	
  ...
  )


  TEST_RUNNER	
  =	
  'django_nose.NoseTestSuiteRunner'
$	
  manage.py	
  test

$	
  manage.py	
  test	
  apps.comments.tests

$	
  manage.py	
  test	
  apps.comments.tests:BlogTestCase

$	
  manage.py	
  test	
  apps.comments.tests:BlogTestCase.test_index



$	
  manage.py	
  test	
  -­‐-­‐with-­‐ids	
  -­‐-­‐failed
$	
  manage.py	
  -­‐-­‐pdb
$	
  manage.py	
  -­‐-­‐pdb-­‐failures
from	
  nose.plugins.attrib	
  import	
  attr

@attr(speed='slow',	
  priority=1)
def	
  test_big_download():
	
  	
  	
  	
  import	
  urllib
	
  	
  	
  	
  #	
  commence	
  slowness..


$	
  nosetests	
  -­‐a	
  speed=slow


$	
  nosetests	
  -­‐a	
  '!slow'


$	
  nosetests	
  -­‐A	
  "(priority	
  >	
  5)	
  and	
  not	
  slow"
TESTING




TESTING
SQLite для
быстрых тестов
 Если ваш проект позволяет
Параллелим тесты
    Нетрудоёмкое ускоение
Ran	
  337	
  tests	
  in	
  326.664s
                    OK	
  (SKIP=2)


1 процесс                                                         326

2 процесса
      Секунды                                   169

3 процесса                               126
                0                  100              200     300         400




                     $	
  ./manage.py	
  -­‐-­‐processes=N
Спасибо за внимание


baryshev@futurecolors.ru
@coagulant                      http://blog.futurecolors.ru/

More Related Content

KEY
Testing My Patience
PDF
UA testing with Selenium and PHPUnit - PFCongres 2013
PDF
Workshop quality assurance for php projects - ZendCon 2013
PDF
Py.test
PDF
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
PDF
Beginning PHPUnit
PDF
Pytest: escreva menos, teste mais
KEY
Django’s nasal passage
Testing My Patience
UA testing with Selenium and PHPUnit - PFCongres 2013
Workshop quality assurance for php projects - ZendCon 2013
Py.test
EPHPC Webinar Slides: Unit Testing by Arthur Purnama
Beginning PHPUnit
Pytest: escreva menos, teste mais
Django’s nasal passage

What's hot (20)

PDF
Python testing using mock and pytest
PDF
Unit testing PHP apps with PHPUnit
PDF
Django (Web Konferencia 2009)
DOCX
inception.docx
PPT
Phpunit testing
KEY
Unit testing with zend framework PHPBenelux
PDF
Unit testing with zend framework tek11
KEY
Unit testing zend framework apps
KEY
Workshop quality assurance for php projects tek12
PDF
Django tutorial 2009
PDF
Building Testable PHP Applications
PDF
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
PDF
New Features PHPUnit 3.3 - Sebastian Bergmann
 
PPT
Mocking Dependencies in PHPUnit
PDF
Practical Celery
PDF
Quality Assurance for PHP projects - ZendCon 2012
PDF
UA testing with Selenium and PHPUnit - TrueNorthPHP 2013
PPTX
Test in action week 2
PDF
Introduction to Unit Testing with PHPUnit
ODP
Testing in Laravel
Python testing using mock and pytest
Unit testing PHP apps with PHPUnit
Django (Web Konferencia 2009)
inception.docx
Phpunit testing
Unit testing with zend framework PHPBenelux
Unit testing with zend framework tek11
Unit testing zend framework apps
Workshop quality assurance for php projects tek12
Django tutorial 2009
Building Testable PHP Applications
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
New Features PHPUnit 3.3 - Sebastian Bergmann
 
Mocking Dependencies in PHPUnit
Practical Celery
Quality Assurance for PHP projects - ZendCon 2012
UA testing with Selenium and PHPUnit - TrueNorthPHP 2013
Test in action week 2
Introduction to Unit Testing with PHPUnit
Testing in Laravel
Ad

Similar to Тестирование и Django (11)

PDF
Django
PDF
Token Testing Slides
PDF
Advanced Django
KEY
What's new in Django 1.2?
ODP
Engitec - Minicurso de Django
PDF
Testing Django Applications
PDF
Django tricks (2)
PDF
DIY in 5 Minutes: Testing Django App with Pytest
PDF
DjangoCon09: The Test Client
KEY
Python在豆瓣的应用
PDF
Intro django
Django
Token Testing Slides
Advanced Django
What's new in Django 1.2?
Engitec - Minicurso de Django
Testing Django Applications
Django tricks (2)
DIY in 5 Minutes: Testing Django App with Pytest
DjangoCon09: The Test Client
Python在豆瓣的应用
Intro django
Ad

More from MoscowDjango (11)

PDF
Пример fuzzy testing для поиска URL в тексте
PDF
TDD или как я стараюсь писать код
PPTX
Cyclone + Eventsource (realtime push-сообщения)
PPT
Производительность в Django
PDF
Django на Android
PDF
Работа со статикой в Django
PPTX
Разработка расширяемых приложений на Django
PPTX
Class Based Generic Views в Django
PPTX
Простой и удобный деплоймент проекта
PPT
Django South. Миграция баз данных.
PDF
Журнальная вёрстка в Django
Пример fuzzy testing для поиска URL в тексте
TDD или как я стараюсь писать код
Cyclone + Eventsource (realtime push-сообщения)
Производительность в Django
Django на Android
Работа со статикой в Django
Разработка расширяемых приложений на Django
Class Based Generic Views в Django
Простой и удобный деплоймент проекта
Django South. Миграция баз данных.
Журнальная вёрстка в Django

Recently uploaded (20)

PDF
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
cuic standard and advanced reporting.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
Approach and Philosophy of On baking technology
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Modernizing your data center with Dell and AMD
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
A Presentation on Artificial Intelligence
PDF
Encapsulation theory and applications.pdf
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
KodekX | Application Modernization Development
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Shreyas Phanse Resume: Experienced Backend Engineer | Java • Spring Boot • Ka...
Spectral efficient network and resource selection model in 5G networks
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
cuic standard and advanced reporting.pdf
Electronic commerce courselecture one. Pdf
Approach and Philosophy of On baking technology
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Modernizing your data center with Dell and AMD
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
A Presentation on Artificial Intelligence
Encapsulation theory and applications.pdf
“AI and Expert System Decision Support & Business Intelligence Systems”
Network Security Unit 5.pdf for BCA BBA.
Review of recent advances in non-invasive hemoglobin estimation
20250228 LYD VKU AI Blended-Learning.pptx
Per capita expenditure prediction using model stacking based on satellite ima...
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
Mobile App Security Testing_ A Comprehensive Guide.pdf
KodekX | Application Modernization Development
CIFDAQ's Market Insight: SEC Turns Pro Crypto

Тестирование и Django

  • 1. Тестирование и Django Илья Барышев @coagulant Moscow Django Meetup №6
  • 5. Пойдёт на пользу вашему проекту
  • 7.        def  test_vin_is_valid(self):                valid_vins  =  ('2G1FK1EJ7B9141175',                                            '11111111111111111',)                for  valid_vin  in  valid_vins:                        self.assertEqual(vin_validator(valid_vin),  None)        def  test_vin_is_invalid(self):                invalid_vins  =  ('abc',  u'M05C0WDJAN60M33TUP6',)                for  invalid_vin  in  invalid_vins:                        self.assertRaises(ValidationError,                              vin_validator,  invalid_vin)
  • 8. Unittest Модели Контекст-процессоры Формы Middleware Views? Template tags, filters
  • 9. Тестируйте поведение А не имплементацию
  • 11. django.test.client.Client def  testPostAsAuthenticatedUser(self):        data  =  self.getValidData(Article.objects.get(pk=1))        self.client.login(username="normaluser",                                              password="normaluser")        self.response  =  self.client.post("/post/",  data)                self.assertEqual(self.response.status_code,  302)        self.assertEqual(Comment.objects.count(),  1)
  • 12. django.test.сlient.RequestFactory def  test_post_ok(self):        request  =  RequestFactory().post(reverse('ch_location'),                                                                        {'location_id':  77})        request.cookies  =  {}        response  =  change_location(request)        self.assertEqual(response.cookies['LOCATION'].value,  '77')        self.assertEqual(response.status_code,  302)
  • 14. def  test_password_recovery_smoke(self):        """        Урлы  восстановления  пароля.        Логика  уже  протестирована  в  django-­‐password-­‐reset        """        response_recover  =  self.client.get(reverse('pass_recover'))                self.assertEqual(response_recover.status_code,  200)                self.assertContains(response_recover,                self.assertTemplateUsed(response_recover,                                                        u'Восстановление  пароля')                                                                'password_reset/recovery_form.html')
  • 17. Покрытие важно Но не делайте из него фетиш
  • 19. >>>  real  =  SomeClass() >>>  my_mock  =  MagicMock(name='method') >>>  real.method  =  my_mock >>>  real.method(3,  4,  5,  key='value') >>>  my_mock.called True >>>  my_mock.call_count 1 >>>  mock.method.assert_called_with(3,  4,  5) Traceback  (most  recent  call  last):    ... AssertionError:  Expected  call:  method(3,  4,  5) Actual  call:  method(3,  4,  5,  key='value')
  • 20. @patch('twitter.Api') def  test_twitter_tag_simple_mock(self,  ApiMock):        api_instance  =  ApiMock.return_value        api_instance.GetUserTimeline.return_value  =  SOME_JSON        output,  context  =  render_template( """{%  load  twitter_tag  %}  {%  get_tweets  for  "jresig"  as  tweets  %}""")        api_instance.GetUserTimeline.assert_called_with(                screen_name='jresig',                  include_rts=True,                  include_entities=True)
  • 21. from  mock  import  patch from  django.conf  import  settings @patch.multiple(settings,  APPEND_SLASH=True,                                MIDDLEWARE_CLASSES=(common_middleware,)) def  test_flatpage_doesnt_require_trailing_slash(self):        form  =  FlatpageForm(data=dict(url='/no_trailing_slash',                                                                      **self.form_data))        self.assertTrue(form.is_valid())
  • 22. from  django.test.utils  import  override_settings @override_settings(        APPEND_SLASH=False,          MIDDLEWARE_CLASSES=(common_middleware,) ) def  test_flatpage_doesnt_require_trailing_slash(self):        form  =  FlatpageForm(data=dict(url='/no_trailing_slash',                                                                      **self.form_data))        self.assertTrue(form.is_valid())
  • 24. [ { "model": "docs.documentrelease", "pk": 1, "fields": { "lang": "en", "version": "dev", "scm": "svn", "scm_url": "http://code.djangoproject.com/svn/django/trunk/docs", "is_default": false } }, { "model": "docs.documentrelease", Обычный тест с "pk": 2, фикстурами "fields": { "lang": "en", "version": "1.0", "scm": "svn", "scm_url": "http://code.djangoproject.com/svn/django/branches/releases/1.0.X/docs", "is_default": false } }, { "model": "docs.documentrelease", "pk": 3, "fields": { "lang": "en", "version": "1.1", "scm": "svn", "scm_url": "http://code.djangoproject.com/svn/django/branches/releases/1.1.X/docs", "is_default": false
  • 25. django-­‐any https://github.com/kmmbvnr/django-­‐any from  django_any  import  any_model class  TestMyShop(TestCase):        def  test_order_updates_user_account(self):                account  =  any_model(Account,  amount=25,                              user__is_active=True)                order  =  any_model(Order,  user=account.user,                        amount=10)                order.proceed()                account  =  Account.objects.get(pk=account.pk)                self.assertEquals(15,  account.amount)
  • 27. import  factory from  models  import  MyUser class  UserFactory(factory.Factory):        FACTORY_FOR  =  MyUser        first_name  =  'John'        last_name  =  'Doe'        admin  =  False
  • 28. #  Инстанс,  сохранённый  в  базу user  =  UserFactory.create() #  Экземпляр  User,  не  сохранённый  в  базу user  =  UserFactory.build() #  Создаём  инстанс  с  конкретыми  значениями user  =  UserFactory.create(name=u'Василий',  age=25)
  • 29. class  UserFactory(factory.Factory):        first_name  =  'Vasily'        last_name  =  'Pupkin'        email  =  factory.LazyAttribute( lambda  u:  '{0}.{1}@example.com'.format( u.first_name,  u.last_name).lower()) >>>  UserFactory().email 'vasily.pupkin@example.com'
  • 30. class  UserWithEmailFactory(UserFactory):        email  =  factory.Sequence( lambda  n:  'person{0}@example.com'.format(n)) >>>  UserFactory().email 'person0@example.com' >>>  UserFactory().email     'person1@example.com'
  • 32. INSTALLED_APPS  =  (        ...        #3rd-­‐party  apps        'south',        'sorl.thumbnail',        'pytils',        'pymorphy',                  'compressor', Несколько сотен        'django_nose', тестов        'django_geoip',        'mptt',        'widget_tweaks',        'guardian',                ...
  • 33. /tests #  -­‐*-­‐  coding:  utf-­‐8  -­‐*-­‐        __init__.py test_archive.py from  test_archive  import  *        test_blog_model.py from  test_blog_model  import  *        test_modified.py from  test_modified  import  *        test_post_model.py from  test_post_model  import  *        test_redactor.py from  test_redactor  import  *        test_views.py from  test_views  import  *        test_cross_post.py from  test_cross_post  import  *
  • 34. django-­‐nose https://github.com/jbalogh/django-­‐nose
  • 35. $  pip  install  django-­‐nose #  settings.py   INSTALLED_APPS  =  (        ...        'django_nose',        ... ) TEST_RUNNER  =  'django_nose.NoseTestSuiteRunner'
  • 36. $  manage.py  test $  manage.py  test  apps.comments.tests $  manage.py  test  apps.comments.tests:BlogTestCase $  manage.py  test  apps.comments.tests:BlogTestCase.test_index $  manage.py  test  -­‐-­‐with-­‐ids  -­‐-­‐failed $  manage.py  -­‐-­‐pdb $  manage.py  -­‐-­‐pdb-­‐failures
  • 37. from  nose.plugins.attrib  import  attr @attr(speed='slow',  priority=1) def  test_big_download():        import  urllib        #  commence  slowness.. $  nosetests  -­‐a  speed=slow $  nosetests  -­‐a  '!slow' $  nosetests  -­‐A  "(priority  >  5)  and  not  slow"
  • 39. SQLite для быстрых тестов Если ваш проект позволяет
  • 40. Параллелим тесты Нетрудоёмкое ускоение
  • 41. Ran  337  tests  in  326.664s OK  (SKIP=2) 1 процесс 326 2 процесса Секунды 169 3 процесса 126 0 100 200 300 400 $  ./manage.py  -­‐-­‐processes=N
  • 42. Спасибо за внимание baryshev@futurecolors.ru @coagulant http://blog.futurecolors.ru/