Slide 1

Slide 1 text

PYCON UK 2015 TESTING DJANGO APPLICATIONS by Iacopo Spalletti @yakkys

Slide 2

Slide 2 text

WHO AM I? Founder and Lead developer @NephilaIt django CMS core developer django CMS installer author

Slide 3

Slide 3 text

TESTING CODE IS IMPORTANT Everyone here does it, right?

Slide 4

Slide 4 text

SELDOM IT'S ENJOYABLE Boilerplate Tests setup To mock ... or not mock?

Slide 5

Slide 5 text

CHORES OF TESTING DJANGO APPLICATIONS Fake project Fake data Fake requests Mock... Mock... Mock...

Slide 6

Slide 6 text

WITH A LITTLE HELPER... Enter djangocms-helper

Slide 7

Slide 7 text

DJANGOCMS-HELPER An addon to help writing testcases Not a replacement for unittest, nose or py.test Does not require django CMS

Slide 8

Slide 8 text

DJANGOCMS-HELPER Provides: Complete Django project Mock helpers Data setup helpers

Slide 9

Slide 9 text

DJANGOCMS-HELPER DJANGO PROJECT Bundled project with: CLI equivalent to django-admin Self configuration (almost) Sample templates

Slide 10

Slide 10 text

DJANGOCMS-HELPER MOCK HELPERS Mocking request, context, login Done in a consistent and tested way

Slide 11

Slide 11 text

DJANGOCMS-HELPER DATA SETUP HELPERS Methods to create: django CMS pages Users Images

Slide 12

Slide 12 text

HOW DO I USE IT? Write the helper file Write tests ... Enjoy

Slide 13

Slide 13 text

HOW DO I USE IT? THE HELPER FILE HELPER_SETTINGS = dict( INSTALLED_APPS=[ ... 'myapp' ] ... ) def run(): from djangocms_helper import runner runner.cms('myapp') if __name__ == '__main__': run()

Slide 14

Slide 14 text

THE HELPER FILE HOW DOES IT WORK? Add the settings needed by your application + Execute the runner

Slide 15

Slide 15 text

THE HELPER FILER HOW DOES IT WORK? 1. Merge app settings with default ones 2. Setup Django 3. Execute the Django commands

Slide 16

Slide 16 text

THE HELPER FILE SETTINGS MAGIC djangocms-helper knows a few things: South / Django migrations Django 1.8 TEMPLATE settings Depedencies and custom configurations for django CMS

Slide 17

Slide 17 text

HOW DO I USE IT? EXECUTING THE HELPER (page-meta)yakky@andalu: ~/myapp $ python cms_helper.py Creating test database for alias 'default'... ........... ------------------------------------------------------- Ran 11 tests in 8.668s OK Destroying test database for alias 'default'... Without arguments it just runs the tests

Slide 18

Slide 18 text

HOW DO I USE IT? EXECUTING THE HELPER Plus built-in commands: server: execute the bundled project so you can interact with it makemigrations: generates migrations (both south and django) compilemessages / makemessages ... any command ... (through call_command)

Slide 19

Slide 19 text

DJANGOCMS-HELPER WRITING TESTS Helpers provided by djangocms_helper.base_test.BaseTestCase

Slide 20

Slide 20 text

HOW DO I USE IT? MOCK HELPERS Generating Request object is tedious and error-prone By default no useful attributes like cookies, session, user etc

Slide 21

Slide 21 text

MOCK HELPERS REQUESTS REQUESTS djangocms-helper ships with: get_request post_request get_page_request a 'special' request for CMS frontend editor

Slide 22

Slide 22 text

MOCK HELPERS CREATING A REQUEST In [1]: request = self.get_request( page=some_page, lang='en', user=some_user, path='/en/', use_middlewares=True ) In [2]: request.COOKIES {} In [3]: request.session In [4]: request.current_page > In [5]: request.user > In [6]: request._messages

Slide 23

Slide 23 text

MOCK HELPERS DJANGO CMS PLUGINS Rendering django CMS plugins in tests is not straightforward Shortcuts to easily test plugin rendering BaseTestCase.get_plugin_context BaseTestCase.render_plugin

Slide 24

Slide 24 text

MOCK HELPERS DJANGO CMS PLUGINS Like this context = self.get_plugin_context(page, 'en', plugin, edit=True) # Render a single plugin rendered_1 = plugin.render_plugin(context, placeholder) # Render a whole placeholder rendered_2 = render_placeholder( placeholder, context, editable=True ) # Render the plugin - Same as rendered_1 but in one pass rendered_3 = self.render_plugin(page, 'en', plugin, edit=True)

Slide 25

Slide 25 text

MOCK HELPERS DJANGO CMS APPHOOKS Helpers to load apphooks during tests: app_page = api.create_page( 'page', 'project.html', 'en', published=True, apphook='MyApp', ) app_page.publish('en') self.reload_urlconf() Call BaseTestCase.reload_urlconf after adding an Apphook

Slide 26

Slide 26 text

MOCK HELPERS USER LOGINS [...] with self.login_user_context(self.user): # this request is made with self.user logged in self.client.get([...]) with self.login_user_context(self.user_staff): # this request is made with self.user_staff logged in self.client.get([...]) BaseTestCase.login_user_context: context manager for authenticated sessions

Slide 27

Slide 27 text

HOW DO I USE IT? CREATING DATA Lots of way of preparing test data: static fixtures custom code data generator (factory-boy et al.) Sometimes they does not fit

Slide 28

Slide 28 text

CREATING DATA DJANGOCMS-HELPER WAY django CMS is the primary target: pages titles users images

Slide 29

Slide 29 text

CREATING DATA DJANGO CMS PAGES class MyTestCase(BaseTestCase): _pages_data = ( {'en': {'title': 'page one', 'template': 'page_meta.html', 'publish': True}, 'fr_FR': {'title': 'page un', 'publish': True}, 'it': {'title': 'pagina uno', 'publish': True}}, {'en': {'title': 'page two', 'template': 'page_meta.html', 'publish': True}, 'fr_FR': {'title': 'page deux', 'publish': True}, 'it': {'title': 'pagina due', 'publish': True}}, ) ... def test_method(self): pages = self.get_pages() Built on top of django CMS API

Slide 30

Slide 30 text

CREATING DATA DJANGO CMS PAGES Supports 'complex' arguments: parent: using the slug of the parent page apphook: reloads the urlconf if any is provided

Slide 31

Slide 31 text

CREATING DATA USERS self.user = self.create_user( 'admin', '[email protected]', 'admin', is_staff=True, is_superuser=True, base_cms_permissions=True, permissions=('add_something',) ) BaseTestCase.create_user knows about custom user models An admin, a staff and a normal user are provided by default in setUpClass

Slide 32

Slide 32 text

CREATING DATA IMAGES Django does not provide any quick way to create images in tests dangocms-helper does: create_image create_django_image_object create_filer_image_object

Slide 33

Slide 33 text

CREATING DATA IMAGES In [1]: self.create_image() In [2]: self.create_django_image_object() In [3]: self.create_filer_image_object()

Slide 34

Slide 34 text

EXAMPLES django-filer djangocms-blog djangocms-page-meta aldryn-events aldryn-newsblog

Slide 35

Slide 35 text

CHECK DOCS FOR MORE http://djangocms-helper.readthedocs.org/

Slide 36

Slide 36 text

ANY QUESTION?

Slide 37

Slide 37 text

GRAZIE!