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

Everything not Tested Will Eventually Fail

Everything not Tested Will Eventually Fail

Slides from my talk at the NYR online Meetup

Colin Fay

July 28, 2020
Tweet

More Decks by Colin Fay

Other Decks in Programming

Transcript

  1. Everything not tested will eventually fail 2020-07-28 - NYC Data

    Hackers Meetup Colin Fay - ThinkR Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 1 / 43
  2. $ whoami Colin FAY Data Scientist & R-Hacker at ThinkR,

    a french company focused on Data Science & R. Hyperactive open source developer, lead developer of the {golem} project. https://thinkr.fr https://rtask.thinkr.fr https://twitter.com/_colinfay https://github.com/colinfay https://colinfay.me Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 2 / 43
  3. Data Science engineering, focused on R. Training Software Engineering R

    in production Consulting ThinkR Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 4 / 43
  4. Everything not tested will eventually fail Testing your {shiny} application

    before production Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 5 / 43
  5. <aside> What does "production" even mean? A piece of software

    that is: USED, even if by only one person RELIED UPON by the user: to be available, and accurate by the developer: to be available, accurate, modular, and resilient HAS REAL LIFE IMPACT on the user, who needs the software on the developer, who works on the software </aside> Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 6 / 43
  6. Everything not tested will eventually fail Part 0, The Current

    State of Unit Test Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 7 / 43
  7. Everything not tested will eventually fail Part 1, Why Colin

    FAY (@_ColinFay) - https://rtask.thinkr.fr 11 / 43
  8. Why Everything That's Not Tested Will Eventually Break Colin FAY

    (@_ColinFay) - https://rtask.thinkr.fr 12 / 43
  9. Why Don't let your users be your unit test Colin

    FAY (@_ColinFay) - https://rtask.thinkr.fr 13 / 43
  10. Why Control the application load See also: Don't DoS your

    own server Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 14 / 43
  11. During dev Safely collaborate & change elements on a project

    Making changes should be pain-free Bugs should be detected quickly New collaborators should be able to integrate a team smoothly Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 15 / 43
  12. In production Safely serve application Your users should not be

    your unit tests Serving application cost money (corollary) You shouldn't spend 1 million bucks on AWS (Jeff Bezos is rich enough) You shouldn't DoS your own server Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 16 / 43
  13. Everything not tested will eventually fail Part 2, What Colin

    FAY (@_ColinFay) - https://rtask.thinkr.fr 17 / 43
  14. What the users see What the users interact with General

    front-end/design What - User Interface Your time is limited, so if you have to choose don't focus too much on testint the UI only Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 18 / 43
  15. Core algorithms that make your app "unique" Business knowledge What

    your users rely on What - Business logic Try to test business logic as extensively as possible Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 19 / 43
  16. How much CPU & RAM does your application need Bad

    estimate will lead to slow application performances If the app needs to scale, it's crucial to kow it upfront What - Application Load Poor app performances lead to bad UX, and potentially cost Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 20 / 43
  17. Everything not tested will eventually fail Part 3, How Colin

    FAY (@_ColinFay) - https://rtask.thinkr.fr 21 / 43
  18. -> Leverage standard testing frameworks test_that("The meaning of life is

    42", { expect_equal( meaning_of_life(), 42 ) }) How - Business logic/backend Shiny App as a package Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 22 / 43
  19. How - User interface/frontend {shinytests} Test visual regression of your

    application puppeteer Command line tool to mock a web session, in NodeJS {crrry} R tool to drive a {shiny} session Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 23 / 43
  20. 1. Records snapshots of an app 2. Replays the application

    3. Detects visual regression How - {shinytests} Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 24 / 43
  21. 1. Records interaction with the application 2. Replays the application

    with NodeJS 3. Detects application logic changes How - puppeteer Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 25 / 43
  22. How - puppeteer // Require the node module const puppeteer

    = require('puppeteer'); (async () => { // launch puppeteer and connect to the page const browser = await puppeteer.launch() const page = await browser.newPage() await page.goto('http://localhost:2811/') // We're waiting for a DOM element to be ready await page.waitForSelector('.row > .col > \ .rounded > details:nth-child(3) > summary') // Now it's ready, we can click on it await page.click('.row > .col > .rounded > \ details:nth-child(3) > summary') // Now our test is over, we can close the connection await browser.close() })() Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 26 / 43
  23. And it has a Chrome extension Records the app "live"

    Returns the NodeJS code to replay the application How - puppeteer Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 27 / 43
  24. Wrapper around the {crrri} , for remote orchestration of Chrome,

    with recipes for {shiny} apps Connects to a running app and interact with it Allows to script everything How - {crrry} Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 28 / 43
  25. How - {crrry} Create a new testing session test <-

    crrry::CrrryOnPage$new( # Find the Chrome binary chrome_bin = pagedown::find_chrome(), # Get a random port for Chrome to use chrome_port = httpuv::randomPort(), # Connect to a page url = "https://connect.thinkr.fr/hexmake/" ) test$wait_for_shiny_ready() Shiny is computing ✔ Shiny is still running Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 29 / 43
  26. How - {crrry} Set a series of input for (i

    in letters[1:3]){ # Set a value for a given input test$shiny_set_input(id = "main_ui_1-left_ui_1-pkg_name_ui_1-package", i) } ── Setting id main_ui_1-left_ui_1-pkg_name_ui_1-package with value a Shiny is computing ✓ Shiny is still running ── Setting id main_ui_1-left_ui_1-pkg_name_ui_1-package with value b Shiny is computing ✓ Shiny is still running ── Setting id main_ui_1-left_ui_1-pkg_name_ui_1-package with value c Shiny is computing ✓ Shiny is still running Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 30 / 43
  27. JavaScript library to simulate a hordes of gremlins using an

    app Will click and scroll at random on the app Allows to detect unexpected behaviors How - gremlins Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 31 / 43
  28. How - gremlins test <- crrry::CrrryOnPage$new( chrome_bin = pagedown::find_chrome(), chrome_port

    = httpuv::randomPort(), url = "https://connect.thinkr.fr/hexmake/", headless = TRUE ) test$wait_for_shiny_ready() # Launch a hordes of gremlins test$gremlins_horde() # Wait for them to finish their work Sys.sleep(20) # Check that everything is ready test$wait_for_shiny_ready() # Stop the test test$stop() Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 32 / 43
  29. How - Testing the app load {shinyloadtest} : native R

    package + Cli to record and replay load tests {dockerstats} : get Docker stats inside R {crrry} + {dockerstats} : replay session and watch the Docker stats Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 33 / 43
  30. Records a visit on the application Replays the app with

    multiple users Gives detailed stats about response time and load How - {shinyloadtest} Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 34 / 43
  31. Wrapper around docker stats Turns the stats from Docker into

    an R dataframe Can be called recursively How - {dockerstats} Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 35 / 43
  32. How - {dockerstats} # Launch the container from the terminal

    docker run --name hexmake --rm -p 2811:80 colinfay/hexmake # Call dockerstats, only selecting specific columns dockerstats::dockerstats("hexmake")[, c("Name", "MemUsage", "CPUPerc", "MemPerc", "record_time")] Warning in system(com, intern = TRUE): running command 'docker stats --no- stream hexmake --format "{{.Container}}, {{.Name}},{{.ID}},{{.CPUPerc}},{{.MemUsage}},{{.NetIO}},{{.BlockIO}}, {{.MemPerc}},{{.PIDs}}"' had status 1 Unable to find any container running. [1] Name MemUsage CPUPerc MemPerc record_time <0 rows> (or 0-length row.names) Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 36 / 43
  33. {dockerstats} + {crrry} # Getting the result from the first

    launch results <- dockerstats::dockerstats("hexmake", extra = "launch") # Setting a series of letters as input for (i in letters[1:10]){ test$shiny_set_input( "main_ui_1-left_ui_1-pkg_name_ui_1-package", i ) # Binding the current snapshot to the results results <- rbind( results, dockerstats::dockerstats("hexmake", extra = i) ) } Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 37 / 43
  34. To conclude Test often, test soon If you have to

    chose, focus on the backend Interactive tests can (and should) be scripted Don't forget to test the load Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 40 / 43
  35. Online [email protected] http://twitter.com/_colinfay http://twitter.com/thinkr_fr https://github.com/ColinFay https://thinkr.fr/ https://rtask.thinkr.fr/ https://colinfay.me/ Related projects

    engineering-shiny.org {golem} {shinipsum} {fakir} {shinysnippets} Thx! Questions? Colin Fay Colin FAY (@_ColinFay) - https://rtask.thinkr.fr 43 / 43