SlideShare una empresa de Scribd logo
1 de 37
Descargar para leer sin conexión
Full-stack webapp testing with Selenium and Rails

• Alex Chaffee

• Brian Takita
Abstract

• Want to test your entire Web 2.0 app, from AJAX and DHTML through browser-rendered
  HTML into a live instance of your application and database? Most web testing frameworks
  have gaps in their coverage: JUnit and Test::Unit miss the client frontend; JSUnit misses the
  server backend; web testing frameworks miss some or all of the JavaScript. With Selenium
  we have a framework that can test the whole application, from browser-executed JavaScript,
  through a live application backend, then back to assertions on browser-rendered DOM code.
  Selenium RC takes this further: since you write your tests in your application language, your
  tests can do data setup and assertions based directly on server-side domain objects that
  may be inaccessible or only partially accessible from the client side. On our teams we have
  used and developed a series of helper methods and assertions that allow testing of AJAX
  and DHTML functions as well.

  In this tutorial we outline the architecture of Selenium RC and walk through code and
  examples illustrating how to do full-stack testing against a Ruby on Rails application.
Selenium Features

• Selenium runs in the browser

• Executes your app in a frame

• Simulates user actions via JavaScript

• Goes all the way to the server and back

• Complementary to JSUnit

   • JSUnit tests JS pages only, not interaction with server

• Fun to watch
First Example

• Basic example (login_test.rb)

   •   def test_login
          open "/"
          assert_text_present("Please sign in")

         type "username", "jdoe"
         type "password", "password"
         click "submit"
         assert_text_present("Welcome, John Doe")

         open "/"
         assert_text_present("Welcome, John Doe")
       end

• Sort of a DSL ("Selenese")

• Written in Ruby

   • Can also use Java, .NET, Python, Perl, etc.
Accessing Your World

• Can access database and/or domain objects

  • def test_signup
      open "/signup"
      assert_text_present("Please sign up")
      type "username", "noob"
      type "fullname", "New Bie"
      type "password", "secret"
      type "password_verify", "secret"
      click "submit"
      assert_text_present("Welcome, New Bie")

      user = User.find_by_username("noob")
      assert user.authenticate("secret")
    end
Or even email!

 • def test_signup_via_email
     open "/signup"
     assert_text_present("Please sign up")
     type "email", "noob@example.com"
     click "submit"
     assert_text_present("An email has been sent to noob@example.com")
     wait_for { !ActionMailer::Base.deliveries.empty? }
     user = User.find_by_email("noob@example.com”)
     assert !user.verified?
     link = extract_link(ActionMailer::Base.deliveries[0].body)
     open link
     wait_for do
       user.reload
       user.verified?
     end
   end

   def extract_link(s)
    /http://S*/.match(s)[0]
   end
Or even email!

 • def test_signup_via_email
     open "/signup"
     assert_text_present("Please sign up")
     type "email", "noob@example.com"
     click "submit"
     assert_text_present("An email has been sent to noob@example.com")
     wait_for { !ActionMailer::Base.deliveries.empty? }
     user = User.find_by_email("noob@example.com”)
     assert !user.verified?
     link = extract_link(ActionMailer::Base.deliveries[0].body)
     open link
     wait_for do
       user.reload
       user.verified?
     end
   end

   def extract_link(s)
    /http://S*/.match(s)[0]
   end
Or even email!

 • def test_signup_via_email
     open "/signup"
     assert_text_present("Please sign up")
     type "email", "noob@example.com"
     click "submit"
     assert_text_present("An email has been sent to noob@example.com")
     wait_for { !ActionMailer::Base.deliveries.empty? }
     user = User.find_by_email("noob@example.com”)
     assert !user.verified?
     link = extract_link(ActionMailer::Base.deliveries[0].body)
     open link
     wait_for do
       user.reload
       user.verified?
     end
   end

   def extract_link(s)
    /http://S*/.match(s)[0]
   end
Or even email!

 • def test_signup_via_email
     open "/signup"
     assert_text_present("Please sign up")
     type "email", "noob@example.com"
     click "submit"
     assert_text_present("An email has been sent to noob@example.com")
     wait_for { !ActionMailer::Base.deliveries.empty? }
     user = User.find_by_email("noob@example.com”)
     assert !user.verified?
     link = extract_link(ActionMailer::Base.deliveries[0].body)
     open link
     wait_for do
       user.reload
       user.verified?
     end
   end

   def extract_link(s)
    /http://S*/.match(s)[0]
   end
Or even email!

 • def test_signup_via_email
     open "/signup"
     assert_text_present("Please sign up")
     type "email", "noob@example.com"
     click "submit"
     assert_text_present("An email has been sent to noob@example.com")
     wait_for { !ActionMailer::Base.deliveries.empty? }
     user = User.find_by_email("noob@example.com”)
     assert !user.verified?
     link = extract_link(ActionMailer::Base.deliveries[0].body)
     open link
     wait_for do
       user.reload
       user.verified?
     end
   end

   def extract_link(s)
    /http://S*/.match(s)[0]
   end
And don’t forget to extract a DSL

    def login(user_name,password)
      open('/login')
      type "id=login", user_name
      type "id=password", password
      click_and_wait "commit"
    end

    def logout
      open('/logout')
    end
Selenium RC Architecture: launch

       rake selenium:test                 rake selenium:server




               Launch                           Launch


        Selenium Test Suite                  Selenium Server                         Browser
                                Launch
                                Browser
                                                                 Launch
                                                                 Browser



                                                                                     DOM/JS

          Webrick running app
           (in "test" mode)




    Database
                                                                 Remote (possibly)
Selenium RC Architecture: run test

        rake selenium:test                         rake selenium:server




                Launch                                   Launch


         Selenium Test Suite                          Selenium Server                         Browser


    def test_foo
                                   click
     click "submit"
                                 'submit'
    end                                                    Selenese
                                                          Interpreter       click
                                                                          'submit'
                                                                                              DOM/JS
                                                                             HTTP
           Webrick running app
                                            HTTP            Proxy
            (in "test" mode)




     Database

                                                                          Remote (possibly)
Multiple Platform Support

• OS (Unix, Windows, Mac)

• Browser (IE, Firefox, Safari)

• The Selenium Farm (Continuous Integration)
Good Things Come To Those Who Wait

• Web 2.0 is Asynchronous and Dynamic

  • The “A” in "AJAX"

  • The "D" in "DHTML"

• The problem:

  • Since they happen unpredicatably, and inside the context of a single page,
    they’re harder to test
Good Things Come To Those Who Wait

• wait_for function

   • executes in Ruby

• wait_for_condition action

   • takes a JavaScript expression, evals it in browser

• wait_for_condition is complementary to wait_for

   • JavaScript can't poll DB or domain objects

   • Write your conditions in the language you prefer
More examples

• Tracker

  • project_page_editing_test



• Peer2Patent

  • create_prior_art_test

  • registration_mode_test
What kind of tests?

• Integration Tests

   • Test multiple layers of your app working together

• Acceptance Tests

   • Test specific customer features and/or scenarios

• UI tests

   • Test complicated or detailed UI widgets

• Smoke Tests

   • Special case of Integration Tests

   • Make sure your app doesn’t blow up
Wait, do you mean Integration Tests or
Integration Tests?

• Selenium tests are integration tests in the abstract

• Not derived from Rails Integration Tests

• Rails ITs are faster

• Selenium tests are better for testing AJAX, DHTML, widgets, full-stack
  integration



• Where you can do a test in Ruby instead of Selenium... you should.
When to use Selenium?

• Test full stack

• Test JS->server interaction

• Test emails

• Smoke testing

• Testing in multiple browsers
Particular Strengths of Selenium Tests

• AJAX/RJS tests

  • Test what state the browser is in after the RJS/AJAX call

• JS tests

  • Test JavaScript interacting with your DOM

  • Not just functional/behavioral JS (which JSUnit is great for)
When not to use Selenium?

• For every edge case

   • Want to test happy path, and one or two error paths

• When speed is of the essence

   • e.g. in a suite you run a lot, or when your tests start taking more than a few minutes

   • see next slide...

• When you’re testing fine-grained features

   • Selenium tests tend to sprawl out

      • setup/teardown are more expensive, so you want to test more things per test

   • Unit tests should be small and isolated
Slow-lenium

• Selenium is much faster than a human, but still much slower than unit tests.
  How do we deal with that?

• Fast Suite / Slow Suite

   • Run Fast suite before checkin

   • Run Slow suite in Continuous Integration

• When appropriate, convert Selenium tests into unit tests

   • Consider bootstrapping with Selenium tests, then replacing them with
     isolated tests once your app is up and running
Locators

• Specify how to locate an HTML element

  • id

     • "id" attribute

     • e.g. id=userName

  • name

     • "name" attribute

     • followed by optional "value" or "index" filter

     • e.g. name=flavor value=chocolate
Locators (cont.)

• identifier

   • first id, then name

• dom

   • JavaScript expression

   • e.g. dom=document.forms['icecreamForm'].flavorDropdown

• xpath

   • e.g. xpath=//a[contains(@href,'#id1')]/@class
Locators (cont.)

• link

   • selects the <A>` element whose Text content matches the given text

   • e.g. link=Click Here To Continue

• css

   • css selector

   • e.g. css=a[href="#id3"]

• Custom Locators

• By default, it's "identifier",

   • or "xpath" if it starts with "//"

   • or "dom" if it starts with "document."
Tips

• use ids when possible

  • XPath makes your tests brittle and dependent on page structure

• use slow mode for debugging

• user_extensions.js
Gotchas

• Disable Transactional Fixtures for Selenium tests

• Reload all fixtures before every test

   • consistent state

   • order-independent

• set allow_concurrency=true

• cookies stay between tests

   • can lead to tests passing when run alone, failing when run together

   • you can eval JS to clear cookies between tests

• Firefox profiles
Test-driving from Selenium

• Some people like it, some don't

• Pro:

   • Top-down

   • When test passes, feature is done

   • Stay close to well-defined customer requirements

• Con:

   • Still vulnerable to edge cases

   • Brittle in the face of UI changes

• You usually iterate through all layers of tests, several times over
Pivotal rake integration

• launches server locally

• runs tests locally and/or remotely
Pivotal Ruby Classes

• selenium_suite.rb

• selenium_helper.rb
Selenium On Rails

• Generates HTML (FIT-style)

• Can't go into your DB or domain

• Any custom test code has to be JavaScript

• Does it work remotely?
Q&A
Experimentation
References

• www.openqa.org—selenium-rc <http://www.openqa.org/selenium-rc/>
Timeline

• 90 minutes with Q&A interspersed
Full-stack webapp testing with Selenium and Rails

Más contenido relacionado

Destacado

Groovy for Java Developers
Groovy for Java DevelopersGroovy for Java Developers
Groovy for Java DevelopersPeter Ledbrook
 
Building domain-specific languages with Groovy
Building domain-specific languages with GroovyBuilding domain-specific languages with Groovy
Building domain-specific languages with GroovyYaroslav Yermilov
 
Behat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и MinkBehat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и Minktyomo4ka
 
Behat-trick: как мы внедряли BDD на наших проектах
Behat-trick: как мы внедряли BDD на наших проектахBehat-trick: как мы внедряли BDD на наших проектах
Behat-trick: как мы внедряли BDD на наших проектахSQALab
 
Concurrency and Multithreading Demistified - Reversim Summit 2014
Concurrency and Multithreading Demistified - Reversim Summit 2014Concurrency and Multithreading Demistified - Reversim Summit 2014
Concurrency and Multithreading Demistified - Reversim Summit 2014Haim Yadid
 
Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)
Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)
Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)SQALab
 
Continuous Delivery in Ruby
Continuous Delivery in RubyContinuous Delivery in Ruby
Continuous Delivery in RubyBrian Guthrie
 
Selenium 2 - PyCon 2011
Selenium 2 - PyCon 2011Selenium 2 - PyCon 2011
Selenium 2 - PyCon 2011hugs
 
Automated Web Testing With Selenium
Automated Web Testing With SeleniumAutomated Web Testing With Selenium
Automated Web Testing With SeleniumDeepak Mittal
 
What Mr. Spock would possibly say about modern unit testing: pragmatic and em...
What Mr. Spock would possibly say about modern unit testing: pragmatic and em...What Mr. Spock would possibly say about modern unit testing: pragmatic and em...
What Mr. Spock would possibly say about modern unit testing: pragmatic and em...Yaroslav Yermilov
 
Browser Automated Testing Frameworks - Nightwatch.js
Browser Automated Testing Frameworks - Nightwatch.jsBrowser Automated Testing Frameworks - Nightwatch.js
Browser Automated Testing Frameworks - Nightwatch.jsLuís Bastião Silva
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in JavaYakov Fain
 
From One to Many: Evolving VPC Design (ARC401) | AWS re:Invent 2013
From One to Many:  Evolving VPC Design (ARC401) | AWS re:Invent 2013From One to Many:  Evolving VPC Design (ARC401) | AWS re:Invent 2013
From One to Many: Evolving VPC Design (ARC401) | AWS re:Invent 2013Amazon Web Services
 
CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...
CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...
CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...CloudIDSummit
 

Destacado (18)

Groovy for Java Developers
Groovy for Java DevelopersGroovy for Java Developers
Groovy for Java Developers
 
Building domain-specific languages with Groovy
Building domain-specific languages with GroovyBuilding domain-specific languages with Groovy
Building domain-specific languages with Groovy
 
A Case Study of Using Selenium IDE and WebDriver_Word Doc
A Case Study of Using Selenium IDE and WebDriver_Word DocA Case Study of Using Selenium IDE and WebDriver_Word Doc
A Case Study of Using Selenium IDE and WebDriver_Word Doc
 
Behat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и MinkBehat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и Mink
 
Behat-trick: как мы внедряли BDD на наших проектах
Behat-trick: как мы внедряли BDD на наших проектахBehat-trick: как мы внедряли BDD на наших проектах
Behat-trick: как мы внедряли BDD на наших проектах
 
Selenium
SeleniumSelenium
Selenium
 
Concurrency and Multithreading Demistified - Reversim Summit 2014
Concurrency and Multithreading Demistified - Reversim Summit 2014Concurrency and Multithreading Demistified - Reversim Summit 2014
Concurrency and Multithreading Demistified - Reversim Summit 2014
 
Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)
Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)
Автоматизация для ленивых тестировщиков. Selenium + Python + Behave (BDD)
 
Continuous Delivery in Ruby
Continuous Delivery in RubyContinuous Delivery in Ruby
Continuous Delivery in Ruby
 
Selenium 2 - PyCon 2011
Selenium 2 - PyCon 2011Selenium 2 - PyCon 2011
Selenium 2 - PyCon 2011
 
Automated Web Testing With Selenium
Automated Web Testing With SeleniumAutomated Web Testing With Selenium
Automated Web Testing With Selenium
 
What Mr. Spock would possibly say about modern unit testing: pragmatic and em...
What Mr. Spock would possibly say about modern unit testing: pragmatic and em...What Mr. Spock would possibly say about modern unit testing: pragmatic and em...
What Mr. Spock would possibly say about modern unit testing: pragmatic and em...
 
Browser Automated Testing Frameworks - Nightwatch.js
Browser Automated Testing Frameworks - Nightwatch.jsBrowser Automated Testing Frameworks - Nightwatch.js
Browser Automated Testing Frameworks - Nightwatch.js
 
Reactive Thinking in Java
Reactive Thinking in JavaReactive Thinking in Java
Reactive Thinking in Java
 
From One to Many: Evolving VPC Design (ARC401) | AWS re:Invent 2013
From One to Many:  Evolving VPC Design (ARC401) | AWS re:Invent 2013From One to Many:  Evolving VPC Design (ARC401) | AWS re:Invent 2013
From One to Many: Evolving VPC Design (ARC401) | AWS re:Invent 2013
 
XPATH
XPATHXPATH
XPATH
 
CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...
CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...
CIS13: Bootcamp: Ping Identity OAuth and OpenID Connect In Action with PingFe...
 
Jmeter
JmeterJmeter
Jmeter
 

Último

Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfSeasiaInfotech2
 

Último (20)

Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
The Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdfThe Future of Software Development - Devin AI Innovative Approach.pdf
The Future of Software Development - Devin AI Innovative Approach.pdf
 

Full-stack webapp testing with Selenium and Rails

  • 1. Full-stack webapp testing with Selenium and Rails • Alex Chaffee • Brian Takita
  • 2. Abstract • Want to test your entire Web 2.0 app, from AJAX and DHTML through browser-rendered HTML into a live instance of your application and database? Most web testing frameworks have gaps in their coverage: JUnit and Test::Unit miss the client frontend; JSUnit misses the server backend; web testing frameworks miss some or all of the JavaScript. With Selenium we have a framework that can test the whole application, from browser-executed JavaScript, through a live application backend, then back to assertions on browser-rendered DOM code. Selenium RC takes this further: since you write your tests in your application language, your tests can do data setup and assertions based directly on server-side domain objects that may be inaccessible or only partially accessible from the client side. On our teams we have used and developed a series of helper methods and assertions that allow testing of AJAX and DHTML functions as well. In this tutorial we outline the architecture of Selenium RC and walk through code and examples illustrating how to do full-stack testing against a Ruby on Rails application.
  • 3. Selenium Features • Selenium runs in the browser • Executes your app in a frame • Simulates user actions via JavaScript • Goes all the way to the server and back • Complementary to JSUnit • JSUnit tests JS pages only, not interaction with server • Fun to watch
  • 4. First Example • Basic example (login_test.rb) • def test_login open "/" assert_text_present("Please sign in") type "username", "jdoe" type "password", "password" click "submit" assert_text_present("Welcome, John Doe") open "/" assert_text_present("Welcome, John Doe") end • Sort of a DSL ("Selenese") • Written in Ruby • Can also use Java, .NET, Python, Perl, etc.
  • 5. Accessing Your World • Can access database and/or domain objects • def test_signup open "/signup" assert_text_present("Please sign up") type "username", "noob" type "fullname", "New Bie" type "password", "secret" type "password_verify", "secret" click "submit" assert_text_present("Welcome, New Bie") user = User.find_by_username("noob") assert user.authenticate("secret") end
  • 6. Or even email! • def test_signup_via_email open "/signup" assert_text_present("Please sign up") type "email", "noob@example.com" click "submit" assert_text_present("An email has been sent to noob@example.com") wait_for { !ActionMailer::Base.deliveries.empty? } user = User.find_by_email("noob@example.com”) assert !user.verified? link = extract_link(ActionMailer::Base.deliveries[0].body) open link wait_for do user.reload user.verified? end end def extract_link(s) /http://S*/.match(s)[0] end
  • 7. Or even email! • def test_signup_via_email open "/signup" assert_text_present("Please sign up") type "email", "noob@example.com" click "submit" assert_text_present("An email has been sent to noob@example.com") wait_for { !ActionMailer::Base.deliveries.empty? } user = User.find_by_email("noob@example.com”) assert !user.verified? link = extract_link(ActionMailer::Base.deliveries[0].body) open link wait_for do user.reload user.verified? end end def extract_link(s) /http://S*/.match(s)[0] end
  • 8. Or even email! • def test_signup_via_email open "/signup" assert_text_present("Please sign up") type "email", "noob@example.com" click "submit" assert_text_present("An email has been sent to noob@example.com") wait_for { !ActionMailer::Base.deliveries.empty? } user = User.find_by_email("noob@example.com”) assert !user.verified? link = extract_link(ActionMailer::Base.deliveries[0].body) open link wait_for do user.reload user.verified? end end def extract_link(s) /http://S*/.match(s)[0] end
  • 9. Or even email! • def test_signup_via_email open "/signup" assert_text_present("Please sign up") type "email", "noob@example.com" click "submit" assert_text_present("An email has been sent to noob@example.com") wait_for { !ActionMailer::Base.deliveries.empty? } user = User.find_by_email("noob@example.com”) assert !user.verified? link = extract_link(ActionMailer::Base.deliveries[0].body) open link wait_for do user.reload user.verified? end end def extract_link(s) /http://S*/.match(s)[0] end
  • 10. Or even email! • def test_signup_via_email open "/signup" assert_text_present("Please sign up") type "email", "noob@example.com" click "submit" assert_text_present("An email has been sent to noob@example.com") wait_for { !ActionMailer::Base.deliveries.empty? } user = User.find_by_email("noob@example.com”) assert !user.verified? link = extract_link(ActionMailer::Base.deliveries[0].body) open link wait_for do user.reload user.verified? end end def extract_link(s) /http://S*/.match(s)[0] end
  • 11. And don’t forget to extract a DSL def login(user_name,password) open('/login') type "id=login", user_name type "id=password", password click_and_wait "commit" end def logout open('/logout') end
  • 12. Selenium RC Architecture: launch rake selenium:test rake selenium:server Launch Launch Selenium Test Suite Selenium Server Browser Launch Browser Launch Browser DOM/JS Webrick running app (in "test" mode) Database Remote (possibly)
  • 13. Selenium RC Architecture: run test rake selenium:test rake selenium:server Launch Launch Selenium Test Suite Selenium Server Browser def test_foo click click "submit" 'submit' end Selenese Interpreter click 'submit' DOM/JS HTTP Webrick running app HTTP Proxy (in "test" mode) Database Remote (possibly)
  • 14. Multiple Platform Support • OS (Unix, Windows, Mac) • Browser (IE, Firefox, Safari) • The Selenium Farm (Continuous Integration)
  • 15. Good Things Come To Those Who Wait • Web 2.0 is Asynchronous and Dynamic • The “A” in "AJAX" • The "D" in "DHTML" • The problem: • Since they happen unpredicatably, and inside the context of a single page, they’re harder to test
  • 16. Good Things Come To Those Who Wait • wait_for function • executes in Ruby • wait_for_condition action • takes a JavaScript expression, evals it in browser • wait_for_condition is complementary to wait_for • JavaScript can't poll DB or domain objects • Write your conditions in the language you prefer
  • 17. More examples • Tracker • project_page_editing_test • Peer2Patent • create_prior_art_test • registration_mode_test
  • 18. What kind of tests? • Integration Tests • Test multiple layers of your app working together • Acceptance Tests • Test specific customer features and/or scenarios • UI tests • Test complicated or detailed UI widgets • Smoke Tests • Special case of Integration Tests • Make sure your app doesn’t blow up
  • 19. Wait, do you mean Integration Tests or Integration Tests? • Selenium tests are integration tests in the abstract • Not derived from Rails Integration Tests • Rails ITs are faster • Selenium tests are better for testing AJAX, DHTML, widgets, full-stack integration • Where you can do a test in Ruby instead of Selenium... you should.
  • 20. When to use Selenium? • Test full stack • Test JS->server interaction • Test emails • Smoke testing • Testing in multiple browsers
  • 21. Particular Strengths of Selenium Tests • AJAX/RJS tests • Test what state the browser is in after the RJS/AJAX call • JS tests • Test JavaScript interacting with your DOM • Not just functional/behavioral JS (which JSUnit is great for)
  • 22. When not to use Selenium? • For every edge case • Want to test happy path, and one or two error paths • When speed is of the essence • e.g. in a suite you run a lot, or when your tests start taking more than a few minutes • see next slide... • When you’re testing fine-grained features • Selenium tests tend to sprawl out • setup/teardown are more expensive, so you want to test more things per test • Unit tests should be small and isolated
  • 23. Slow-lenium • Selenium is much faster than a human, but still much slower than unit tests. How do we deal with that? • Fast Suite / Slow Suite • Run Fast suite before checkin • Run Slow suite in Continuous Integration • When appropriate, convert Selenium tests into unit tests • Consider bootstrapping with Selenium tests, then replacing them with isolated tests once your app is up and running
  • 24. Locators • Specify how to locate an HTML element • id • "id" attribute • e.g. id=userName • name • "name" attribute • followed by optional "value" or "index" filter • e.g. name=flavor value=chocolate
  • 25. Locators (cont.) • identifier • first id, then name • dom • JavaScript expression • e.g. dom=document.forms['icecreamForm'].flavorDropdown • xpath • e.g. xpath=//a[contains(@href,'#id1')]/@class
  • 26. Locators (cont.) • link • selects the <A>` element whose Text content matches the given text • e.g. link=Click Here To Continue • css • css selector • e.g. css=a[href="#id3"] • Custom Locators • By default, it's "identifier", • or "xpath" if it starts with "//" • or "dom" if it starts with "document."
  • 27. Tips • use ids when possible • XPath makes your tests brittle and dependent on page structure • use slow mode for debugging • user_extensions.js
  • 28. Gotchas • Disable Transactional Fixtures for Selenium tests • Reload all fixtures before every test • consistent state • order-independent • set allow_concurrency=true • cookies stay between tests • can lead to tests passing when run alone, failing when run together • you can eval JS to clear cookies between tests • Firefox profiles
  • 29. Test-driving from Selenium • Some people like it, some don't • Pro: • Top-down • When test passes, feature is done • Stay close to well-defined customer requirements • Con: • Still vulnerable to edge cases • Brittle in the face of UI changes • You usually iterate through all layers of tests, several times over
  • 30. Pivotal rake integration • launches server locally • runs tests locally and/or remotely
  • 31. Pivotal Ruby Classes • selenium_suite.rb • selenium_helper.rb
  • 32. Selenium On Rails • Generates HTML (FIT-style) • Can't go into your DB or domain • Any custom test code has to be JavaScript • Does it work remotely?
  • 33. Q&A
  • 36. Timeline • 90 minutes with Q&A interspersed