Slide 1

Slide 1 text

QZUFTU IFMQTZPVXSJUFCFUUFS %KBOHPBQQT "OESFBT1FMNF %KBOHP$PO&VSPQF 4MJEFTIUUQTQFBLFSEFDLDPNQFMNF personalkollen

Slide 2

Slide 2 text

5PQJDT w5FTUJOHJO%KBOHPPWFSWJFX w*OUSPEVDUJPOUPQZUFTU w%KBOHPBOEQZUFTU w5FTUPSHBOJ[BUJPO w'BTUFSUFTUSVOT wQZUFTUpYUVSFT

Slide 3

Slide 3 text

5FTUJOHJO%KBOHP

Slide 4

Slide 4 text

BGVMMGFBUVSFE1ZUIPOUFTUJOHUPPM QZUFTU

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

1MVHJOT w%KBOHPQZUFTUEKBOHP w%JTUSJCVUFEQBSBMMFMJ[FEQZUFTUYEJTU w-PHDBQUVSFQZUFTUDBQUVSFMPH w$PWFSBHFSFQPSUJOHQZUFTUDPW wBOENBOZNPSF wIUUQQZUFTUPSHMBUFTUQMVHJOTIUNMFYUFSOBM QMVHJOT

Slide 7

Slide 7 text

XJUIPVUCPJMFSQMBUF 1ZUIPOJDUFTUT

Slide 8

Slide 8 text

%FNPUJNF

Slide 9

Slide 9 text

%FNP#FGPSF from  django.test  import  TestCase   ! class  TestHelloWorld(TestCase):          def  test_hello_world(self):                  response  =  self.client.get('/')   !                self.assertEqual(response.status_code,  200)                  self.assertIn('Hello',                                              response.content.decode('utf-­‐8'))

Slide 10

Slide 10 text

%FNP"GUFS def  test_hello_world(client):          response  =  client.get('/')   !        assert  response.status_code  ==  200          assert  'Hello'  ==  response.content.decode('utf-­‐8')

Slide 11

Slide 11 text

%FNPUJNF w"TTFSUJPOTXJUIBTTFSUTUBUFNFOU w/P5FTU$BTFTVCDMBTTJOH wQZUFTUpYUVSFTGPSUFTUEFQFOEFODJFT

Slide 12

Slide 12 text

*OUFHSBUJPOCFUXFFOQZUFTUBOE%KBOHP QZUFTUEKBOHP

Slide 13

Slide 13 text

*OTUBMMTQZUFTUEKBOHPBOEQZUFTU pip  install  pytest-­‐django

Slide 14

Slide 14 text

"EETZPVSQSPKFDUUP1ZUIPOQBUI SFRVJSFTTFUVQQZUPCFQSFTFOU pip  install  -­‐e  .

Slide 15

Slide 15 text

"WFSZNJOJNBMTFUVQQZ from  setuptools  import  setup   setup(name='yourproject',  version='1.0')

Slide 16

Slide 16 text

$POpHVSFTFUUJOHTJOQZUFTUJOJ [pytest] DJANGO_SETTINGS_MODULE=settings

Slide 17

Slide 17 text

%KBOHP5FTU$BTFT KVTUXPSLT

Slide 18

Slide 18 text

3VOOJOHUIFUFTUT

Slide 19

Slide 19 text

3VOBMMUIFUFTUT $  py.test

Slide 20

Slide 20 text

3VOBMMUFTUTJOBTQFDJpDpMF $  py.test  test_views.py

Slide 21

Slide 21 text

3VOBMMUFTUDBTFTUIBUBSFOBNFE UFTU@GPP $  py.test  -­‐k  test_foo

Slide 22

Slide 22 text

5FTUPSHBOJ[BUJPO

Slide 23

Slide 23 text

#ZEFGBVMU UFTUTBSFGPVOEJO test_*.py

Slide 24

Slide 24 text

$POpHVSBCMFJOQZUFTUJOJ [pytest] python_files  =  check_*.py

Slide 25

Slide 25 text

5FTUTDBOMJWFVOEFS%KBOHPBQQT polls/tests/views.py blog/tests/views.py

Slide 26

Slide 26 text

5FTUTDBOMJWFJOUIFJSPXOSPPUEJSFDUPSZ tests/polls/views.py tests/blog/models.py

Slide 27

Slide 27 text

5FTUTCFTQMJUVQJOUPEJGGFSFOUSPPU EJSFDUPSJFT unit_tests/blog/models.py integration_tests/test_foo.py   browser_tests/test_login.py

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

testing Running tests

Slide 30

Slide 30 text

5FTUEBUBCBTFSFVTF

Slide 31

Slide 31 text

3FVTFEBUBCBTFGSPNMBTUSVO py.test  -­‐-­‐reuse-­‐db

Slide 32

Slide 32 text

1VUUIJTJOQZUFTUJOJUPBMXBZTSFVTFUIF EBUBCBTF ! ! [pytest] addopts  =  -­‐-­‐reuse-­‐db

Slide 33

Slide 33 text

3FDSFBUFEBUBCBTFTDIFNBXIFOEPJOH NPEFMDIBOHFT py.test  -­‐-­‐reuse-­‐db  -­‐-­‐create-­‐db

Slide 34

Slide 34 text

.BLFVTFPGUIPTFFYUSBDPSFT 3VOUFTUTJOQBSBMMFM

Slide 35

Slide 35 text

YEJTUQSPWJEFTEJTUSJCVUFEUFTUJOH pip  install  pytest-­‐xdist

Slide 36

Slide 36 text

3VOUFTUTJOGPVSQBSBMMFMQSPDFTTFT $  py.test  -­‐n  4

Slide 37

Slide 37 text

QZUFTUEKBOHPBOEEBUBCBTFT

Slide 38

Slide 38 text

5IJTXJMMBMMPXEBUBCBTFBDDFTT import  pytest ! @pytest.mark.django_db   def  test_user_count():        assert  User.objects.count()  ==  0

Slide 39

Slide 39 text

5IJTXJMMGBJM EBUBCBTFBDDFTTJTOPU BMMPXFE def  test_user_count():        assert  User.objects.count()  ==  0

Slide 40

Slide 40 text

! ! ! ___________  test_user_count  ____________   test_db_access.py:4:  in  test_user_count   >      assert  User.objects.count()  ==  0   ! ... ! E      Failed:  Database  access  not  allowed,        use  the  "django_db"  mark  to  enable

Slide 41

Slide 41 text

.BSLBOFOUJSFNPEVMFGPSEBUBCBTF VTBHF import  pytest   ! pytestmark  =  pytest.mark.django_db   ! def  test_foo():          pass   def  test_bar():          pass

Slide 42

Slide 42 text

3VOBMMUFTUTXIJDIEPFTOPUUPVDIUIF EBUBCBTF $  py.test  -­‐m  'not  django_db'

Slide 43

Slide 43 text

3FQMBDFNFOUGPSVOJUUFTUTFU6QUFBS%PXO QZUFTUpYUVSFT

Slide 44

Slide 44 text

[{"pk":  1,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐09T09:10:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐08-­‐09T09:40:00Z",  "logged_time":  31946}},  {"pk":  2,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐10T09:00:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐08-­‐10T09:30:00Z",  "logged_time":  32038}},  {"pk":  3,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐08-­‐10T09:10:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐10T09:40:00Z",  "logged_time":  32039}},  {"pk":  4,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐11T09:10:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐11T09:40:00Z",  "logged_time":   32104}},  {"pk":  5,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐11T09:00:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐08-­‐11T09:30:00Z",  "logged_time":  32105}},  {"pk":  6,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐12T09:00:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐08-­‐12T09:30:00Z",  "logged_time":  32161}},  {"pk":  7,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐08-­‐12T09:10:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐12T09:40:00Z",  "logged_time":  32162}},  {"pk":  8,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐15T15:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐15T16:00:00Z",  "logged_time":   32390}},  {"pk":  9,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐22T09:00:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐08-­‐22T09:30:00Z",  "logged_time":  32784}},  {"pk":  10,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐23T09:00:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐08-­‐23T09:30:00Z",  "logged_time":  32838}},  {"pk":  11,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐08-­‐24T09:00:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐24T09:30:00Z",  "logged_time":  32903}},  {"pk":  12,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐25T09:00:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐25T09:30:00Z",  "logged_time":   32964}},  {"pk":  13,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐26T09:00:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐08-­‐26T09:30:00Z",  "logged_time":  33029}},  {"pk":  14,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐29T12:00:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐08-­‐29T12:30:00Z",  "logged_time":  33244}},  {"pk":  15,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐08-­‐29T15:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐29T16:00:00Z",  "logged_time":  33253}},  {"pk":  16,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐30T11:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐08-­‐30T12:00:00Z",  "logged_time":   33281}},  {"pk":  17,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐30T12:00:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐08-­‐30T12:30:00Z",  "logged_time":  33283}},  {"pk":  18,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐08-­‐31T12:00:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐08-­‐31T12:30:00Z",  "logged_time":  33341}},  {"pk":  19,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐09-­‐01T11:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐01T12:00:00Z",  "logged_time":  33400}},  {"pk":  20,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐01T15:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐01T16:00:00Z",  "logged_time":   33414}},  {"pk":  21,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐02T11:30:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐09-­‐02T12:00:00Z",  "logged_time":  33453}},  {"pk":  22,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐02T15:30:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐09-­‐02T16:00:00Z",  "logged_time":  33475}},  {"pk":  23,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐09-­‐02T12:00:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐02T12:30:00Z",  "logged_time":  33484}},  {"pk":  24,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐03T09:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐03T10:00:00Z",  "logged_time":   33579}},  {"pk":  25,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐03T10:00:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐09-­‐03T10:30:00Z",  "logged_time":  33586}},  {"pk":  26,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐03T10:30:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐09-­‐03T11:00:00Z",  "logged_time":  33587}},  {"pk":  27,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐09-­‐03T12:00:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐03T12:30:00Z",  "logged_time":  33589}},  {"pk":  28,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐03T12:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐03T13:00:00Z",  "logged_time":   33591}},  {"pk":  29,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐04T09:30:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐09-­‐04T10:00:00Z",  "logged_time":  33700}},  {"pk":  30,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐04T12:00:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐09-­‐04T12:30:00Z",  "logged_time":  33702}},  {"pk":  31,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐09-­‐04T12:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐04T13:00:00Z",  "logged_time":  33703}},  {"pk":  32,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐05T12:00:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐05T12:30:00Z",  "logged_time":   33732}},  {"pk":  33,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐05T12:00:00Z",  "is_scheduled":  true,  "stop":   "2011-­‐09-­‐05T12:30:00Z",  "logged_time":  33734}},  {"pk":  34,  "model":  "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐05T15:30:00Z",   "is_scheduled":  true,  "stop":  "2011-­‐09-­‐05T16:00:00Z",  "logged_time":  33744}},  {"pk":  35,  "model":  "tracker.loggedtimebreak",  "fields":   {"start":  "2011-­‐09-­‐06T11:30:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐06T12:00:00Z",  "logged_time":  33794}},  {"pk":  36,  "model":   "tracker.loggedtimebreak",  "fields":  {"start":  "2011-­‐09-­‐06T12:00:00Z",  "is_scheduled":  true,  "stop":  "2011-­‐09-­‐06T12:30:00Z",  "logged_time":   %KBOHPpYUVSFQZUFTUpYUVSF

Slide 45

Slide 45 text

(FUBOJOTUBODFPGUIFUFTUDMJFOU ! def  test_with_client(client):          response  =  client.get('/foo/')        assert  response.status_code  ==  200  

Slide 46

Slide 46 text

%FNPUJNF

Slide 47

Slide 47 text

%FpOJOHBpYUVSF QVUUIJTJODPOGUFTUQZ import  pytest   from  selenium.webdriver  import  Firefox   ! @pytest.yield_fixture(scope='session')   def  webdriver():          driver  =  Firefox()          yield  driver          driver.quit()

Slide 48

Slide 48 text

8JMMIBWF'JSFGPYTUBSUFEXIFOUIFUFTU SVOT def  test_hello(live_server,  webdriver):          webdriver.get(live_server.url  +  '/')          h1  =  (webdriver                      .find_element_by_css_selector('h1'))   !        assert  h1.text  ==  'Hello  Djangocon'

Slide 49

Slide 49 text

3FRVFTU%KBOHPEBUBCBTFBDDFTT JOBpYUVSF import  pytest   ! ! @pytest.fixture   def  person_in_db(db):          return  Person.objects.create(                  name='Andreas')  

Slide 50

Slide 50 text

3FRVFTU%KBOHPEBUBCBTFBDDFTT JOBpYUVSF import  pytest   from  factories  import  PersonFactory   ! @pytest.fixture   def  person_in_db(db):          return  PersonFactory.create(                  name='Andreas')   Use factory_boy for creating test model data

Slide 51

Slide 51 text

.PSFpYUVSFTGFBUVSFT w1BSBNFUSJ[BUJPO w4DPQJOH SFVTFFYQFOTJWFTFUVQ  w"VUPVTFpYUVSFT

Slide 52

Slide 52 text

8PSLTXJUICPUI XPSMET

Slide 53

Slide 53 text

(SFBUSFTPVSDFT w$BSM.FZFS 5FTUJOHBOE%KBOHP 1Z$PO w%KBOHPUFTUJOHCFTUQSBDUJDFT wIUUQXXXZPVUVCFDPNXBUDI WJDL/2D/9J4 ! w)PMHFS,SFLFM QZUFTUSBQJEBOETJNQMFUFTUJOHXJUI1ZUIPO  &VSP1ZUIPO wIUUQXXXZPVUVCFDPNXBUDI WL;+)6N;9. ! wQZUFTUEPDVNFOUBUJPO wIUUQQZUFTUPSH ! wQZUFTUEKBOHPEPDVNFOUBUJPO wIUUQQZUFTUEKBOHPSFBEUIFEPDTPSH

Slide 54

Slide 54 text

&NBJMBOESFBT!QFMNFTF 5XJUUFS!BOESFBTQFMNF *3$QZMJCPO'SFFOPEF
 4MJEFTIUUQTQFBLFSEFDLDPNQFMNF 2VFTUJPOT