Тестирование      и Django      Илья Барышев       @coagulant Moscow Django Meetup №6
Защита отрегрессий
Быстрыеизменения  в коде
Меняет подход кнаписанию кода
Пойдёт на пользу вашему проекту
Модульноетестирование
 	  	  	  def	  test_vin_is_valid(self):	  	  	  	  	  	  	  	  valid_vins	  =	  (2G1FK1EJ7B9141175,	  	  	  	  	  	  	  	...
UnittestМодели      Контекст-процессорыФормы       MiddlewareViews?      Template tags, filters
Тестируйте поведение     А не имплементацию
Функциональное тестирование
django.test.client.Clientdef	  testPostAsAuthenticatedUser(self):	  	  	  	  data	  =	  self.getValidData(Article.objects....
django.test.сlient.RequestFactorydef	  test_post_ok(self):	  	  	  	  request	  =	  RequestFactory().post(reverse(ch_locat...
Smoke Testing
def	  test_password_recovery_smoke(self):         	  	  	  	  """         	  	  	  	  Урлы	  восстановления	  пароля.     ...
Как мы тестируем
ContiniousIntegration
Покрытие важно  Но не делайте из него фетиш
mockhttp://www.voidspace.org.uk/python/mock/
>>>	  real	  =	  SomeClass()>>>	  my_mock	  =	  MagicMock(name=method)>>>	  real.method	  =	  my_mock>>>	  real.method(3,	...
@patch(twitter.Api)def	  test_twitter_tag_simple_mock(self,	  ApiMock):	  	  	  	  api_instance	  =	  ApiMock.return_value...
from	  mock	  import	  patchfrom	  django.conf	  import	  settings@patch.multiple(settings,	  APPEND_SLASH=True,	  	  	  	...
from	  django.test.utils	  import	  override_settings@override_settings(	  	  	  	  APPEND_SLASH=False,	  	  	  	  	  MIDD...
Фикстуры
[    {         "model": "docs.documentrelease",         "pk": 1,         "fields": {           "lang": "en",           "ve...
django-­‐any                            https://github.com/kmmbvnr/django-­‐anyfrom	  django_any	  import	  any_modelclass...
factory_boyhttps://github.com/dnerdy/factory_boy
import	  factoryfrom	  models	  import	  MyUserclass	  UserFactory(factory.Factory):	  	  	  	  FACTORY_FOR	  =	  MyUser	 ...
#	  Инстанс,	  сохранённый	  в	  базуuser	  =	  UserFactory.create()#	  Экземпляр	  User,	  не	  сохранённый	  в	  базуuse...
class	  UserFactory(factory.Factory):	  	  	  	  first_name	  =	  Vasily	  	  	  	  last_name	  =	  Pupkin	  	  	  	  emai...
class	  UserWithEmailFactory(UserFactory):	  	  	  	  email	  =	  factory.Sequence(                   lambda	  n:	  person...
Django test runner     SUCKS
INSTALLED_APPS	  =	  (	  	  	  	  ...	  	  	  	  #3rd-­‐party	  apps	  	  	  	  south,	  	  	  	  sorl.thumbnail,	  	  	  ...
/tests                               #	  -­‐*-­‐	  coding:	  utf-­‐8	  -­‐*-­‐	  	  	  	  __init__.py                test_...
django-­‐nose          https://github.com/jbalogh/django-­‐nose
$	  pip	  install	  django-­‐nose  #	  settings.py	    INSTALLED_APPS	  =	  (  	  	  	  	  ...  	  	  	  	  django_nose,  ...
$	  manage.py	  test$	  manage.py	  test	  apps.comments.tests$	  manage.py	  test	  apps.comments.tests:BlogTestCase$	  m...
from	  nose.plugins.attrib	  import	  attr@attr(speed=slow,	  priority=1)def	  test_big_download():	  	  	  	  import	  ur...
TESTINGTESTING
SQLite длябыстрых тестов Если ваш проект позволяет
Параллелим тесты    Нетрудоёмкое ускоение
Ran	  337	  tests	  in	  326.664s                    OK	  (SKIP=2)1 процесс                                               ...
Спасибо за вниманиеbaryshev@futurecolors.ru@coagulant                      http://blog.futurecolors.ru/
Upcoming SlideShare
Loading in …5
×

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

1,855 views

Published on

Когда тестировать, что тестировать, как тестировать, Как ускорить тесты и упростить их написание. Отказываемся от классических фикстур в пользу динамически создаваемых моделей.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,855
On SlideShare
0
From Embeds
0
Number of Embeds
92
Actions
Shares
0
Downloads
18
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

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

  1. 1. Тестирование и Django Илья Барышев @coagulant Moscow Django Meetup №6
  2. 2. Защита отрегрессий
  3. 3. Быстрыеизменения в коде
  4. 4. Меняет подход кнаписанию кода
  5. 5. Пойдёт на пользу вашему проекту
  6. 6. Модульноетестирование
  7. 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,  uM05C0WDJAN60M33TUP6,)                for  invalid_vin  in  invalid_vins:                        self.assertRaises(ValidationError,                              vin_validator,  invalid_vin)
  8. 8. UnittestМодели Контекст-процессорыФормы MiddlewareViews? Template tags, filters
  9. 9. Тестируйте поведение А не имплементацию
  10. 10. Функциональное тестирование
  11. 11. django.test.client.Clientdef  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. 12. django.test.сlient.RequestFactorydef  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)
  13. 13. Smoke Testing
  14. 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)
  15. 15. Как мы тестируем
  16. 16. ContiniousIntegration
  17. 17. Покрытие важно Но не делайте из него фетиш
  18. 18. mockhttp://www.voidspace.org.uk/python/mock/
  19. 19. >>>  real  =  SomeClass()>>>  my_mock  =  MagicMock(name=method)>>>  real.method  =  my_mock>>>  real.method(3,  4,  5,  key=value)>>>  my_mock.calledTrue>>>  my_mock.call_count1>>>  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. 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. 21. from  mock  import  patchfrom  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. 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())
  23. 23. Фикстуры
  24. 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. 25. django-­‐any https://github.com/kmmbvnr/django-­‐anyfrom  django_any  import  any_modelclass  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)
  26. 26. factory_boyhttps://github.com/dnerdy/factory_boy
  27. 27. import  factoryfrom  models  import  MyUserclass  UserFactory(factory.Factory):        FACTORY_FOR  =  MyUser        first_name  =  John        last_name  =  Doe        admin  =  False
  28. 28. #  Инстанс,  сохранённый  в  базуuser  =  UserFactory.create()#  Экземпляр  User,  не  сохранённый  в  базуuser  =  UserFactory.build()#  Создаём  инстанс  с  конкретыми  значениямиuser  =  UserFactory.create(name=uВасилий,  age=25)
  29. 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().emailvasily.pupkin@example.com
  30. 30. class  UserWithEmailFactory(UserFactory):        email  =  factory.Sequence( lambda  n:  person{0}@example.com.format(n))>>>  UserFactory().emailperson0@example.com>>>  UserFactory().email    person1@example.com
  31. 31. Django test runner SUCKS
  32. 32. INSTALLED_APPS  =  (        ...        #3rd-­‐party  apps        south,        sorl.thumbnail,        pytils,        pymorphy,                  compressor, Несколько сотен        django_nose, тестов        django_geoip,        mptt,        widget_tweaks,        guardian,                ...
  33. 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. 34. django-­‐nose https://github.com/jbalogh/django-­‐nose
  35. 35. $  pip  install  django-­‐nose #  settings.py   INSTALLED_APPS  =  (        ...        django_nose,        ... ) TEST_RUNNER  =  django_nose.NoseTestSuiteRunner
  36. 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. 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"
  38. 38. TESTINGTESTING
  39. 39. SQLite длябыстрых тестов Если ваш проект позволяет
  40. 40. Параллелим тесты Нетрудоёмкое ускоение
  41. 41. Ran  337  tests  in  326.664s OK  (SKIP=2)1 процесс 3262 процесса Секунды 1693 процесса 126 0 100 200 300 400 $  ./manage.py  -­‐-­‐processes=N
  42. 42. Спасибо за вниманиеbaryshev@futurecolors.ru@coagulant http://blog.futurecolors.ru/

×