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

RRUG - Efficient Testing

Makar Ermokhin
March 14, 2024
34

RRUG - Efficient Testing

I tried to summarise years of working with TestProf and help those who have yet to start. The presentation mostly touches the let_it_be and before_all helpers and problems developers could face when start using that

Makar Ermokhin

March 14, 2024
Tweet

Transcript

  1. Dzień dobry! • Work in Chattermill since 2023 • Live

    in Warsaw since 2021 • Work with Ruby since 2015 • Love tests since 2015 Wake up, samurai, we have some tests to optimise
  2. 13

  3. 14

  4. 15

  5. 16

  6. build_stubbed • Doesn’t save the records 👍 • Doesn’t allow

    records to access database 👍 • Doesn’t help with tests like requests 😕 21
  7. before(:all) • Helps with amount of records created 👍 •

    Provokes state leaks between f iles 😕 • Destroying records is also slow 😕 • Advised against in RSpec docs 😕 • Has a dedicated RuboCop https://docs.rubocop.org/rubocop-rspec/ cops_rspec.html#rspecbeforeafterall 😕 35
  8. Transactions • Begin a transaction • Create records • Run

    tests (each in an individual transaction) • Rollback the transaction (much faster than destroying) • … and that’s pretty much what Test Prof’s before_all & let_it_be does. 37
  9. before_all • Starts a transaction • Executes the block •

    Rollbacks the transaction after tests • No state leak outside of f ile, reloading prevents the leaks within the f ile 38
  10. let_it_be • Does the same in one line • reload

    modi f ier might be moved to the rails_helper 39
  11. It’s not that simple • Simple let - > let_it_be

    replacement might not work • Sometimes your tests might need serious rearrangement 44
  12. It’s not that simple ❌ undef i ned local variable

    or method `user' • Simple let - > let_it_be replacement might not work • Sometimes your tests might need serious rearrangement 45
  13. It’s not that simple ❌ Validation failed: User can't be

    blank • Simple let - > let_it_be replacement might not work • let_it_be is run in before(:all) hook • Sometimes your tests might need serious rearrangement 46
  14. It’s not that simple • Simple let - > let_it_be

    replacement might not work • let_it_be is run in before(:all) hook • let_it_be is order dependent • Sometimes your tests might need serious rearrangement 47
  15. It’s not that simple ❌ • Simple let - >

    let_it_be replacement might not work • let_it_be is run in before(:all) hook • let_it_be is order dependent • Sometimes your tests might need serious rearrangement 48
  16. It’s not that simple • Simple let - > let_it_be

    replacement might not work • let_it_be is run in before(:all) hook • let_it_be is order dependent • let_it_be doesn’t update associations automatically • Sometimes your tests might need serious rearrangement ✅ ✅ 49
  17. State leaks are possible • Even with reload modi f

    ier, we still might have some state leaks • It is because reload doesn’t work within before_all / before(:all) hooks 50
  18. State leaks are possible • Even with reload modi f

    ier, we still might have some state leaks • It is because reload doesn’t work within before_all / before(:all) hooks • Possible solutions: reload manually, freeze objects with freeze modi f ier to prevent updates 51
  19. 53

  20. let vs let_it_be • let_it_be is a good default •

    Suite consisting of one test doesn’t require let_it_be (though it won’t hurt) • Non-factory declarations could bene f it from let • Some suites might bene f it from preferring let to let_it_be 57
  21. Non-factory declarations • Don’t create anything and therefore don’t slow

    us too much • Can use the "partial" rede f ining • let_it_be declarations can be used in let, but not vice versa 59
  22. Complex suites • Way one: pre-create posts & users using

    let_it_be with di ff erent attributes and test with that data • Way two: create data per test using let / let! 61
  23. Complex suites • let_it_be: • E ff icient 👍 •

    Adding a new orderable f ield might force you to rewrite the whole suite 😕 62
  24. Complex suites • let / let!: • Ine ff icient

    😕 • Doesn’t add complexity when editing tests / code 👍 63
  25. Complex suites • How big is gain from using let_it_be?

    • How stable is the list of attributes? • In the end, less e ff icient but more "maintainable" solution might be preferable. It’s Ruby, after all. 66
  26. AnyFixture • Creates one record for whole run that you

    can re-use • Might provoke state leaks between f iles (make sure to reload) • Adding just one f ixture may give a signi f icant improvement • https://test-prof.evilmartians.io/recipes/any_ f ixture 68
  27. Parallelising by f ile • On CI, our tests are

    currently split by example between 4 workers • The feeling is, it decreases the gain we’re getting from let_it_be • The possible side e ff ect: CI nodes become unbalanced • Experiment shows: • RSpec time for slowest node decreased from 6:12 to 5:33 (-11%) • The di ff erence was consumed by CI operations (7:18 vs 7:13) 69