Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testing Django applications with py.test (EuroPython 2013)

Testing Django applications with py.test (EuroPython 2013)

Andreas Pelme

July 05, 2013
Tweet

More Decks by Andreas Pelme

Other Decks in Programming

Transcript

  1. 5FTUJOH%KBOHPBQQMJDBUJPOT
    XJUI
    QZUFTU
    "OESFBT1FMNF
    BOESFBT!QFMNFTF
    !BOESFBTQFMNF
    personalkollen
    fredag 5 juli 13

    View Slide

  2. 5PQJDT
    w5FTUJOHJO%KBOHP
    wQZUFTU
    w%KBOHPBOEQZUFTU
    w%KBOHPUFTUJOHUJQTUSJDLT
    fredag 5 juli 13

    View Slide

  3. 5FTUJOHJO%KBOHP
    fredag 5 juli 13

    View Slide

  4. %KBOHP`TUFTUJOH
    EPDVNFOUBUJPO
    fredag 5 juli 13

    View Slide

  5. %KBOHPEPDVNFOUBUJPO
    l*GZPV`WFCFFOVTJOH1ZUIPO
    GPSBXIJMF EPDUFTUXJMM
    QSPCBCMZGFFMNPSF
    lQZUIPOJDzz
    fredag 5 juli 13

    View Slide

  6. %KBOHP`TUFTUJOH
    EPDVNFOUBUJPO
    fredag 5 juli 13

    View Slide

  7. fredag 5 juli 13

    View Slide

  8. %KBOHP`TUFTUSVOOFS
    fredag 5 juli 13

    View Slide

  9. *UJTHFUUJOHCFUUFS
    Photo: http://www.flickr.com/photos/bee/3290452839/
    fredag 5 juli 13

    View Slide

  10. 0UIFSUFTUJOHUPPMT
    OPTF
    UPY
    5XJTUFE5SJBM
    [PQFUFTUSVOOFS
    fredag 5 juli 13

    View Slide

  11. BGVMMGFBUVSFE1ZUIPOUFTUJOHUPPM
    QZUFTU
    fredag 5 juli 13

    View Slide

  12. TJY .PJO.PJO
    fredag 5 juli 13

    View Slide

  13. 1MVHJOT
    w%JTUSJCVUFEQBSBMMFMJ[FE QZUFTUYEJTU

    w%KBOHP QZUFTUEKBOHP

    w-PHDBQUVSF QZUFTUDBQUVSFMPH

    w$PWFSBHFSFQPSUJOH QZUFTUDPW

    wBOENBOZNPSF
    fredag 5 juli 13

    View Slide

  14. XJUIPVUCPJMFSQMBUF
    1ZUIPOJDUFTUT
    fredag 5 juli 13

    View Slide

  15. from  django.test  import  TestCase
    class  TestHelloWorld(TestCase):
           def  test_hello_world(self):
                   response  =  self.client.get('/hi/')
                   self.assertEqual(response.status_code,
                                                     200)
                   self.assertEqual(response.content,
                                                     'Hello  World!')
    fredag 5 juli 13

    View Slide

  16. def  test_hello_world(client):
           response  =  client.get('/hi/')
         assert  response.status_code  ==  200
         assert  response.content  ==  'Hello  World!'
    fredag 5 juli 13

    View Slide

  17. def  test_hello_world(client):
           response  =  client.get('/hi/')
         assert  response.status_code  ==  200
         assert  response.content  ==  'Hello  World!'
    fredag 5 juli 13

    View Slide

  18. $  py.test
    F
    ===================  FAILURES  ====================
    _______________  test_hello_world  ________________
    client  =  0x1065f58d0>
       def  test_hello_world(client):
             response  =  client.get('/hi/')
             assert  response.status_code  ==  200
    >        assert  response.content  ==  'Hello  World!'
    E        assert  'Hello  EuroPython!'  ==  'Hello  World!'
    E            -­‐  Hello  EuroPython!
    E            +  Hello  World!
    test_hello_world.py:5:  AssertionError
    fredag 5 juli 13

    View Slide

  19. assertAlmostEqual
    assertAlmostEquals
    assertDictContainsSubset
    assertDictEqual
    assertEqual
    assertEquals
    assertFalse
    assertGreater
    assertGreaterEqual
    assertIn
    assertIs
    assertIsInstance
    assertIsNone
    assertIsNot
    assertIsNotNone
    assertItemsEqual
    assertLess
    assertLessEqual
    assertListEqual
    assertMultiLineEqual
    assertNotAlmostEqual
    assertNotAlmostEquals
    assertNotEqual
    assertNotEquals
    assertNotIn
    assertNotIsInstance
    assertNotRegexpMatches
    assertRaises
    assertRaisesRegexp
    assertRegexpMatches
    assertSequenceEqual
    assertSetEqual
    assertTrue
    assertTupleEqual
    fredag 5 juli 13

    View Slide

  20. *OUFHSBUJPOCFUXFFOQZUFTUBOE%KBOHP
    QZUFTUEKBOHP
    fredag 5 juli 13

    View Slide

  21. *OTUBMMTQZUFTUEKBOHPBOEQZUFTU
    pip  install  pytest-­‐django
    fredag 5 juli 13

    View Slide

  22. "EETZPVSQSPKFDUUP1ZUIPOQBUI
    SFRVJSFTBTFUVQQZUPCFQSFTFOU

    pip  install  -­‐e  .
    fredag 5 juli 13

    View Slide

  23. %FpOF%KBOHPTFUUJOHTJOZPVSTIFMM
    FOWJSPONFOU
    export  DJANGO_SETTINGS_MODULE=settings
    fredag 5 juli 13

    View Slide

  24. #POVT
    -BVODIB1ZUIPOTIFMM
    XJUIPVUNBOBHFQZ
    Photo: http://www.flickr.com/photos/mark_i_geo/3498456758
    fredag 5 juli 13

    View Slide

  25. $BOBMTPCFDPOpHVSFEJOQZUFTUJOJ
    [pytest]
    DJANGO_SETTINGS_MODULE=settings
    fredag 5 juli 13

    View Slide

  26. )PXUPSVOUIFUFTUT
    fredag 5 juli 13

    View Slide

  27. 3VOBMMUIFUFTUT
    $  py.test
    fredag 5 juli 13

    View Slide

  28. 3VOBMMUFTUTJOBTQFDJpDpMF
    $  py.test  test_views.py
    fredag 5 juli 13

    View Slide

  29. 3VOBMMUFTUDBTFTUIBUBSFOBNFE
    [email protected]
    $  py.test  -­‐k  test_foo
    fredag 5 juli 13

    View Slide

  30. 8IFSFUPQVUUIFUFTUT
    fredag 5 juli 13

    View Slide

  31. #ZEFGBVMU UFTUTBSFGPVOEJO
    test_*.py
    fredag 5 juli 13

    View Slide

  32. $POpHVSBCMFJOQZUFTUJOJ
    [pytest]
    python_files  =  *.py
    fredag 5 juli 13

    View Slide

  33. 5FTUTDBOMJWFVOEFS%KBOHPBQQT
    polls/tests/views.py
    blog/tests/views.py
    fredag 5 juli 13

    View Slide

  34. 5FTUTDBOMJWFJOUIFJSPXOSPPUEJSFDUPSZ
    tests/polls/views.py
    tests/blog/models.py
    fredag 5 juli 13

    View Slide

  35. 5FTUTCFTQMJUVQJOUPEJGGFSFOUSPPU
    EJSFDUPSJFT
    unit_tests/blog/models.py
    functional_tests/test_foo.py
    fredag 5 juli 13

    View Slide

  36. %KBOHP5FTU$BTFT
    KVTUXPSLT
    fredag 5 juli 13

    View Slide

  37. 3FVTFEBUBCBTFGSPNMBTUSVO
    py.test  -­‐-­‐reuse-­‐db
    fredag 5 juli 13

    View Slide

  38. 1VUUIJTJOQZUFTUJOJUPBMXBZTSFVTFUIF
    EBUBCBTF
    1BTTDSFBUFECUPGPSDFSFDSFBUJPO
    [pytest]
    addopts  =  -­‐-­‐reuse-­‐db
    fredag 5 juli 13

    View Slide

  39. 5FTUBCMF%KBOHPDPEF
    fredag 5 juli 13

    View Slide

  40. .JãLP)FWFSZ
    l5IFSFJTOPTFDSFUUPXSJUJOH
    UFTUTUIFSFBSFPOMZTFDSFUT
    UPXSJUJOHUFTUBCMFDPEFz
    fredag 5 juli 13

    View Slide

  41. NPEFMTQZ
    WJFXTQZ
    fredag 5 juli 13

    View Slide

  42. NPEFMTQZ
    WJFXTQZ
    BENJOQZ
    GPSNTQZ
    fredag 5 juli 13

    View Slide

  43. NPEFMTQZ
    WJFXTQZ
    BENJOQZ
    GPSNTQZ
    [email protected]
    [email protected]
    [email protected]
    fredag 5 juli 13

    View Slide

  44. ,FFQUIFNTNBMM GFXCSBODIFT

    5FTUJOHWJFXT
    fredag 5 juli 13

    View Slide

  45. from  datetime  import  datetime,  time
    from  django.http  import  HttpResponse
    def  greet(request):
           now  =  datetime.now().time()
           if  time(5)  <  now  <  time(12):
                   greeting  =  'morning'
           elif  time(18)  <  now  <  time(21):
                   greeting  =  'evening'
           else:
                   greeting  =  'day'
           return  HttpResponse('Good  %s!'  %  greeting)
    fredag 5 juli 13

    View Slide

  46. from  datetime  import  datetime,  time
    from  django.http  import  HttpResponse
    def  greet(request):
           now  =  datetime.now().time()
           if  time(5)  <  now  <  time(12):
                   greeting  =  'morning'
           elif  time(18)  <  now  <  time(21):
                   greeting  =  'evening'
           else:
                   greeting  =  'day'
           return  HttpResponse('Good  %s!'  %  greeting)
    fredag 5 juli 13

    View Slide

  47. #  greeter.py
    from  datetime  import  time
    def  greeting_at(time_of_day):
           if  time(5)  <  time_of_day  <  time(12):
                   return  'morning'
           elif  time(18)  <  time_of_day  <  time(21):
                   return  'evening'
           else:
                   return  'day'
    fredag 5 juli 13

    View Slide

  48. #  views.py
    from  datetime  import  time
    from  django.http  import  HttpResponse
    from  .greeter  import  greeting_at
    def  greet(request):
           now  =  datetime.now().time()
           greeting  =  greeting_at(now)
           return  HttpResponse('Good  %s!'  %
                                                   greeting)
    fredag 5 juli 13

    View Slide

  49. NBLFTZPVSUFTUTTMPX
    %BUBCBTFBDDFTT
    fredag 5 juli 13

    View Slide

  50. fredag 5 juli 13

    View Slide

  51. UFTUJOH
    UFTUJOH
    fredag 5 juli 13

    View Slide

  52. 5IF03.CMVSTUIFMJOFCFUXFFO
    BQQMJDBUJPODPEFBOERVFSZDPEF
    4FQBSBUFUIFRVFSZDPEFJOUPJUTPXO
    NFUIPET
    .JOEZPVSRVFSJFT
    fredag 5 juli 13

    View Slide

  53. fredag 5 juli 13

    View Slide

  54. !
    6'"
    fredag 5 juli 13

    View Slide

  55. fredag 5 juli 13

    View Slide

  56. QZUFTUEKBOHPBOEEBUBCBTFT
    fredag 5 juli 13

    View Slide

  57. 5IJTXJMMBMMPXEBUBCBTFBDDFTT
    import  pytest
    @pytest.mark.django_db
    def  test_user_count():
           assert  User.objects.count()  ==  0
    fredag 5 juli 13

    View Slide

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

    View Slide

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

    View Slide

  60. .BSLBOFOUJSFNPEVMFGPSEBUBCBTF
    VTBHF
    import  pytest
    pytestmark  =  pytest.mark.django_db
    def  test_foo():  pass
    def  test_bar():  pass
    fredag 5 juli 13

    View Slide

  61. 3VOBMMUFTUTXIJDIEPFTOPUUPVDIUIF
    EBUBCBTF
    $  py.test  -­‐m  'not  django_db'
    fredag 5 juli 13

    View Slide

  62. .PEFMUFTUEBUB
    w$SFBUFPCKFDUTNBOVBMMZ
    w%KBOHPpYUVSFT
    w'BDUPSJFT
    fredag 5 juli 13

    View Slide

  63. %KBOHPpYUVSFT
    [{"model": "myapp.person",
    "pk": 1,
    "fields": {"first_name": "John",
    "last_name": "Lennon"}},
    {"model": "myapp.person",
    "pk": 2,
    "fields": {"first_name": "Paul",
    "last_name": "McCartney"}}
    ]
    Slow & hard to maintain.. avoid them!
    fredag 5 juli 13

    View Slide

  64. [email protected]
    5IFTPMVUJPOGBDUPSJFT
    fredag 5 juli 13

    View Slide

  65. from  django.db  import  models
    class  Group(models.Model):
           name  =  models.TextField()
    class  Person(models.Model):
           first_name  =  models.TextField()
           last_name  =  models.TextField()
           group  =  models.ForeignKey(Group)
           def  group_letter(self):
                   return  self.group.name[0].upper()
    fredag 5 juli 13

    View Slide

  66. import  factory
    from  yourapp.models  import  Person,  Group
    class  GroupFactory(factory.Factory):
           FACTORY_FOR  =  Group
           name  =  'Developers'
    class  PersonFactory(factory.Factory):
           FACTORY_FOR  =  Person
           first_name  =  'John'
           last_name  =  'Doe'
           group  =  factory.SubFactory(GroupFactory)
    fredag 5 juli 13

    View Slide

  67. from  yourfactories  import  PersonFactory
    def  test_group_letter():
           person  =  PersonFactory.build(
                   group__name='admins')
           assert  person.group_letter()  ==  'A'
    fredag 5 juli 13

    View Slide

  68. import  pytest
    @pytest.mark.django_db
    def  test_group_letter():
           person  =  PersonFactory.create(
                   group__name='admins')
           assert  person.group_letter()  ==  'A'
    fredag 5 juli 13

    View Slide

  69. 3FQMBDFNFOUGPSVOJUUFTUTFU6QUFBS%PXO
    QZUFTUpYUVSFT
    fredag 5 juli 13

    View Slide

  70. (FUBOJOTUBODFPGUIFUFTUDMJFOU
    def  test_with_client(client):
           response  =  client.get('/foo/')
           assert  response.status_code  ==  200
    fredag 5 juli 13

    View Slide

  71. 5IFTFUUJOHTXJMMCFBVUPNBUJDBMMZSFTFU
    BGUFSUIFUFTU
    def  test_foo(settings):
           settings.DATE_FORMAT  =  'Y-­‐m-­‐d'
    fredag 5 juli 13

    View Slide

  72. $SFBUFZPVSPXOpYUVSFTXJUI
    QZUFTUpYUVSF
    import  pytest
    @pytest.fixture
    def  person():
           return  PersonFactory.build()
    fredag 5 juli 13

    View Slide

  73. 3FRVFTU%KBOHPEBUBCBTFBDDFTT
    JOBpYUVSF
    import  pytest
    from  your_factories  import  UserFactory
    @pytest.fixture
    def  person_in_db(db):
           return  PersonFactory.create()
    fredag 5 juli 13

    View Slide

  74. (SFBUSFTPVSDFT
    w $BSM.FZFS 5FTUJOHBOE%KBOHP 1Z$PO
    w %KBOHPUFTUJOHCFTUQSBDUJDFTBOEJOTQJSBUJPOGPSUIJTUBML
    w IUUQXXXZPVUVCFDPNXBUDI WJDL/2D/9J4
    w )PMHFS,SFLFM QZUFTUSBQJEBOETJNQMFUFTUJOHXJUI1ZUIPO
    &VSP1ZUIPO
    w IUUQXXXZPVUVCFDPNXBUDI WL;+)6N;9.
    w QZUFTUEPDVNFOUBUJPO
    w IUUQQZUFTUPSH
    w QZUFTUEKBOHPEPDVNFOUBUJPO
    w IUUQQZUFTUEKBOHPSFBEUIFEPDTPSH
    fredag 5 juli 13

    View Slide

  75. QZUFTUTQSJOU
    fredag 5 juli 13

    View Slide

  76. 8PSLTXJUICPUI
    XPSMET
    fredag 5 juli 13

    View Slide

  77. 4MJEFTIUUQTQFBLFSEFDLDPNQFMNF
    BOESFBT!QFMNFTF
    !BOESFBTQFMNF
    5IBOL:PV
    fredag 5 juli 13

    View Slide