Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Integration Testing in Python

37,850 views

Published on

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.

Published in: Technology

Integration Testing in Python

  1. 1. Integration Testing In Python And why I Love it so Much Mike Leone Panoptic Development February 29, 2012
  2. 2. What are web application integration tests?
  3. 3. High-level TESTS
  4. 4. High-level TESTS That simulate Web Browser Interaction
  5. 5. A.K.A. Acceptance Testing Browser Testing
  6. 6. Web apps? Unit testing? Integration testing?
  7. 7. EXAMPLE Test that a user can log in to your web app
  8. 8. EXAMPLE
  9. 9. USE CASES?
  10. 10. Customer-tracked user stories
  11. 11. Customer-tracked user stories “ A user should be able to create a profile and update their address”
  12. 12. High-level tests that span multiple components
  13. 13. High-level tests that span multiple components Beyond the scope of unit tests
  14. 14. Large, inherited applications
  15. 15. Large, inherited applications A less overwhelming way to track big feature sets
  16. 16. Non-application updates
  17. 17. Non-application updates Testing client applications after a data migration or infrastructure upgrades
  18. 18. But integration tests can test low-level logic too!
  19. 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
  21. 22. Pick your Battles <ul><li>Integration tests are SLOW </li></ul>
  22. 23. Pick your Battles <ul><li>Integration tests are SLOW
  23. 24. There's more state to manage </li></ul>
  24. 25. Pick your Battles <ul><li>Integration tests are SLOW
  25. 26. There's more state to manage
  26. 27. They take longer to update </li></ul>
  27. 28. Pick your Battles <ul><li>Integration tests are SLOW
  28. 29. There's more state to manage
  29. 30. They take longer to update </li></ul>
  30. 31. Very simple app or CMS?
  31. 32. Very simple app or CMS? <ul>An integration-only test suite may make sense </ul>
  32. 33. Existing tools
  33. 34. Existing tools: Bare-metal selenium
  34. 35. import xmlrpclib # Make an object to represent the XML-RPC server. server_url = &quot;http://localhost:8080/selenium-driver/RPC2&quot; 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('&quot;C:Program FilesMozilla Firefoxfirefox.exe&quot;' + '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()
  35. 36. import xmlrpclib # Make an object to represent the XML-RPC server. server_url = &quot;http://localhost:8080/selenium-driver/RPC2&quot; 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('&quot;C:Program FilesMozilla Firefoxfirefox.exe&quot;' + '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
  36. 37. import xmlrpclib # Make an object to represent the XML-RPC server. server_url = &quot;http://localhost:8080/selenium-driver/RPC2&quot; 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('&quot;C:Program FilesMozilla Firefoxfirefox.exe&quot;' + '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
  37. 38. Existing tools: Splinter
  38. 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 &quot;Yes, the official website was found!&quot; else: print &quot;No, it wasn't found... We need to improve our SEO techniques&quot; browser.quit()
  39. 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 &quot;Yes, the official website was found!&quot; else: print &quot;No, it wasn't found... We need to improve our SEO techniques&quot; browser.quit() Much better!
  40. 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 &quot;Yes, the official website was found!&quot; else: print &quot;No, it wasn't found... We need to improve our SEO techniques&quot; browser.quit() Much better! But... <ul><li>Still have to manage browser object
  41. 42. Navigation still a bit clunky </li></ul>
  42. 43. The Ruby community is obsessed With testing
  43. 44. The Ruby community is obsessed With testing How do they do it?
  44. 45. # Example: Capybara test framework include Rack::Test::Methods def test_it_says_welcome get '/' click 'link text' assert response.body.include?(“Welcome!”) end
  45. 46. # Example: Capybara test framework include Rack::Test::Methods def test_it_says_welcome get '/' click 'link text' assert response.body.include?(“Welcome!”) end
  46. 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
  47. 48. Enter easy_integration!
  48. 49. Enter easy_integration! The lightweight testing lib I wrote.
  49. 50. easy_integration <ul><li>Runs on top of splinter </li></ul>
  50. 51. easy_integration <ul><li>Runs on top of splinter </li><ul><ul><li>Which runs on top of selenium </li></ul></ul></ul>
  51. 52. easy_integration <ul><li>Runs on top of splinter </li><ul><ul><li>Which runs on top of selenium </li></ul></ul><li>No browser object management </li></ul>
  52. 53. easy_integration <ul><li>Runs on top of splinter </li><ul><ul><li>Which runs on top of selenium </li></ul></ul><li>No browser object management
  53. 54. Smart defaults: </li><ul><ul><li>Chrome browser
  54. 55. Test server running, port 8001 </li></ul></ul></ul>
  55. 56. easy_integration Tiny, simple API: <ul><ul><ul><li>visit()
  56. 57. click()
  57. 58. fill_in()
  58. 59. select()
  59. 60. displays() </li></ul></ul></ul>
  60. 61. easy_integration Tiny, simple API: <ul><ul><ul><li>visit()
  61. 62. click()
  62. 63. fill_in()
  63. 64. select()
  64. 65. displays() </li></ul></ul></ul>That's it
  65. 66. DEMO TIME (Django example)
  66. 67. Other tools: <ul><ul><ul><li>Nose
  67. 68. Lettuce </li></ul></ul></ul>
  68. 69. Still challenging for complex django apps <ul><li>Manage test server
  69. 70. Manage time-consuming database transactions </li></ul>
  70. 71. Coming in Django 1.4 <ul><li>LiveServerTestCase </li></ul>
  71. 72. Questions? <ul><li>https://github.com/mleone
  72. 73. https://github.com/mleone/easy-integration
  73. 74. http://www.panopticdev.com/ </li></ul>

×