Integration Testing in Python

download Integration Testing in Python

If you can't read please download the document

description

This presentation addresses web app integration testing (a.k.a. browser testing) in Python. It focuses on currently-available tools, including one that I wrote, and looks at some specific integration testing concerns for the Django web framework.

Transcript of Integration Testing in Python

  • 1. Integration Testing In Python And why I Love it so Much Mike Leone Panoptic Development February 29, 2012

2. What are web application integration tests? 3. High-level TESTS 4. High-level TESTS That simulate Web Browser Interaction 5. A.K.A. Acceptance Testing Browser Testing 6. Web apps? Unit testing? Integration testing? 7. EXAMPLE Test that a user can log in toyour web app 8. EXAMPLE 9. USE CASES? 10. Customer-tracked user stories 11. Customer-tracked user stories A user should be able to create a profile and update their address 12. High-level tests that span multiple components 13. High-level tests that span multiple components Beyond the scope of unit tests 14. Large, inherited applications 15. Large, inherited applications A less overwhelming way to track big feature sets 16. Non-application updates 17. Non-application updates Testing client applications after a data migration or infrastructure upgrades 18. But integration tests can test low-level logic too! 19. But integration tests can test low-level logic too! So let's write integration tests only, and forgo unit tests! 20. 21. Pick your Battles 22. Pick your Battles

  • Integration tests are SLOW

23. Pick your Battles

  • Integration tests are SLOW

24. There's more state to manage 25. Pick your Battles

  • Integration tests are SLOW

26. There's more state to manage 27. They take longer to update 28. Pick your Battles

  • Integration tests are SLOW

29. There's more state to manage 30. They take longer to update 31. Very simple app or CMS? 32. Very simple app or CMS?

  • An integration-only test suite may make sense

33. Existing tools 34. Existing tools: Bare-metal selenium 35. import xmlrpclib # Make an object to represent the XML-RPC server. server_url = "http://localhost:8080/selenium-driver/RPC2" app = xmlrpclib.ServerProxy(server_url) # Bump timeout a little higher than the default 5 seconds app.setTimeout(15) import os #os.system('start run_firefox.bat') os.system('"C:Program FilesMozilla Firefoxfirefox.exe"' +'http://localhost:8080/selenium-driver/SeleneseRunner.html') print app.open('http://localhost:8080/AUT/000000A/http/www.google.com/') print app.verifyTitle('Google') print app.type('q','Selenium ThoughtWorks') print app.verifyValue('q','Selenium ThoughtWorks') print app.clickAndWait('btnG') print app.verifyTextPresent('selenium.thoughtworks.com','') print app.verifyTitle('Google Search: Selenium ThoughtWorks') print app.testComplete() 36. import xmlrpclib # Make an object to represent the XML-RPC server. server_url = "http://localhost:8080/selenium-driver/RPC2" app = xmlrpclib.ServerProxy(server_url) # Bump timeout a little higher than the default 5 seconds app.setTimeout(15) import os #os.system('start run_firefox.bat') os.system('"C:Program FilesMozilla Firefoxfirefox.exe"' +'http://localhost:8080/selenium-driver/SeleneseRunner.html') print app.open('http://localhost:8080/AUT/000000A/http/www.google.com/') print app.verifyTitle('Google') print app.type('q','Selenium ThoughtWorks') print app.verifyValue('q','Selenium ThoughtWorks') print app.clickAndWait('btnG') print app.verifyTextPresent('selenium.thoughtworks.com','') print app.verifyTitle('Google Search: Selenium ThoughtWorks') print app.testComplete() Too much boilerplate 37. import xmlrpclib # Make an object to represent the XML-RPC server. server_url = "http://localhost:8080/selenium-driver/RPC2" app = xmlrpclib.ServerProxy(server_url) # Bump timeout a little higher than the default 5 seconds app.setTimeout(15) import os #os.system('start run_firefox.bat') os.system('"C:Program FilesMozilla Firefoxfirefox.exe"' +'http://localhost:8080/selenium-driver/SeleneseRunner.html') print app.open('http://localhost:8080/AUT/000000A/http/www.google.com/') print app.verifyTitle('Google') print app.type('q','Selenium ThoughtWorks') print app.verifyValue('q','Selenium ThoughtWorks') print app.clickAndWait('btnG') print app.verifyTextPresent('selenium.thoughtworks.com','') print app.verifyTitle('Google Search: Selenium ThoughtWorks') print app.testComplete() Too much boilerplate Too verbose, API too big 38. Existing tools: Splinter 39. from splinter.browser import Browser browser = Browser() browser.visit('http://google.com') browser.fill('q', 'splinter - python acceptance testing for web applications') browser.find_by_css('.lsb').first.click() if browser.is_text_present('splinter.cobrateam.info'): print "Yes, the official website was found!" else: print "No, it wasn't found... We need to improve our SEO techniques" browser.quit() 40. from splinter.browser import Browser browser = Browser() browser.visit('http://google.com') browser.fill('q', 'splinter - python acceptance testing for web applications') browser.find_by_css('.lsb').first.click() if browser.is_text_present('splinter.cobrateam.info'): print "Yes, the official website was found!" else: print "No, it wasn't found... We need to improve our SEO techniques" browser.quit() Much better! 41. from splinter.browser import Browser browser = Browser() browser.visit('http://google.com') browser.fill('q', 'splinter - python acceptance testing for web applications') browser.find_by_css('.lsb').first.click() if browser.is_text_present('splinter.cobrateam.info'): print "Yes, the official website was found!" else: print "No, it wasn't found... We need to improve our SEO techniques" browser.quit() Much better! But...

  • Still have to manage browser object

42. Navigation still a bit clunky 43. TheRubycommunityis obsessed With testing 44. TheRubycommunityis obsessed With testing How do they do it? 45. # Example: Capybara test framework include Rack::Test::Methods def test_it_says_welcome get '/' click 'link text' assert response.body.include?(Welcome!) end 46. # Example: Capybara test framework include Rack::Test::Methods def test_it_says_welcome get '/' click 'link text' assert response.body.include?(Welcome!) end 47. # Example: Capybara test framework include Rack::Test::Methods def test_it_says_welcome get '/' click 'link text' assert response.body.include?(Welcome!) end That's what I want 48. Entereasy_integration! 49. Entereasy_integration! The lightweight testing lib I wrote. 50. easy_integration

  • Runs on top of splinter

51. easy_integration

  • Runs on top of splinter
    • Which runs on top of selenium

52. easy_integration

  • Runs on top of splinter
    • Which runs on top of selenium

No browser object management 53. easy_integration

  • Runs on top of splinter
    • Which runs on top of selenium

No browser object management 54. Smart defaults:

    • Chrome browser
  • 55. Test server running, port 8001

56. easy_integration Tiny, simple API:

      • visit()
    • 57. click()
  • 58. fill_in()

59. select() 60. displays() 61. easy_integration Tiny, simple API:

      • visit()
    • 62. click()
  • 63. fill_in()

64. select() 65. displays() That's it 66. DEMO TIME (Django example) 67. Other tools:

      • Nose
    • 68. Lettuce

69. Still challenging for complex django apps

  • Manage test server

70. Manage time-consuming database transactions 71. Coming in Django 1.4

  • LiveServerTestCase

72. Questions?

  • https://github.com/mleone

73. https://github.com/mleone/easy-integration 74. http://www.panopticdev.com/