onbetrouwbare TESTS

TESTS DIE SOMS FALEN

  • "Oh ja, die test faalt wel eens"
  • Sneeuwbaleffect in de testsuite
  • Veel voorkomend probleem
  • "non deterministic tests", "flaky tests", "random tests", "erratic tests", "brittle tests", "flickering tests" of zelfs "heisentests"

onbetrouwbare tests

  • Kan in de kosten lopen
  • Veel werk om te verhelpen
  • Houden pipelines en deployments tegen
  • Onbetrouwbare test kan wijzen op onderliggende fouten

Patronen

die leiden tot onbetrouwbare tests

Hard coded ids

  • Postgres gebruikt sequences voor ids
  • Auto increment (1, 2, 3)
  • Test frameworks doen vaak een rollback
  • Rollbacks resetten niet de sequences
  • assert_equal Ivaldo.last.id, 1

Hard coded ids

ActiveRecord::Base.transaction do
   puts Ivaldo.create!.id
   # 1
   raise ActiveRecord::Rollback
end 

puts Ivaldo.create!.id
# 2

database ordering

  • Aannames over de volgorde
  • Niet-gesorteerde collecties
  • Zelfs ordering op id is nodig
 

Database ordering

[8] pry(main)> User.order('id desc').find_by(name: 'sam').id 
User Load (7.6ms) SELECT "users".* FROM "users" WHERE "users"."name" = 'sam' ORDER BY id desc LIMIT 1 
=> 25527 

[9] pry(main)> User.order('id').find_by(name: 'sam').id 
User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."name" = 'sam' ORDER BY id LIMIT 1 
=> 2498
 
[10] pry(main)> User.find_by(name: 'sam').id 
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."name" = 'sam' LIMIT 1 
​=> 9931

Aannames over tijd

  • 16:55 uur onze tijd 
  • Japan: 23:55 uur
  • Records van 'vandaag' kunnen andere uitkomst hebben
  • Timecop!

Aannames over tijd

sleep 0.001
assert(elapsed < 1) 

Aannames over tijd

sleep 0.001
assert(elapsed < 1) 
  • Bij een hoge load kunnen CPU hold ups ontstaan

 

  • Onvoldoende time outs in integratie tests
  • Klik op een link, check of er een element is
  • Tijd wanneer een element gerenderd is

Global state

  • Test past globale variabelen aan die niet gereset worden
  • Falende tests in bepaalde volgorde​
  • Dit kan ook voorkomen bij caching
  • Tests uitvoeren in willekeurige volgorde

Global state

class Frog
   cattr_accessor :total_jumps
   attr_accessor :jumps

   def jump
     Frog.total_jumps = (Frog.total_jumps || 0) + 1
     self.jumps = (self.jumps || 0) + 1
   end
end

def test_global_tracking
   assert(Frog.total_jumps.nil?)
end

def test_jumpy
   frog = Frog.new
   frog.jump
   assert(frog.jumps == 1)
end 

Aannames over omgeving

  • Logica wat anders werkt in verschillende omgevingen
  • Bijvoorbeeld afbeeldingen downloaden indien genoeg ruimte
  • Test faalt indien schijfruimte niet opgehaald mag worden

Resource leaks

  • Integratietests op grote schaal
  • Event handlers niet opruimen
  • Snelle tests kunnen traag worden of helemaal stuk gaan door lekken
  • v8 heat dumps na testen om geheugengebruik van Chrome in de gaten te houden
  • Verwarrend op testomgevingen met mindere 'prestaties'

Problemen aanpakken

  • Verwijderen en vergeten
    • Minder test coverage, scheelt tijd
    • 100 tests / 100%, 200 tests / 60%
  • Opnieuw uitvoeren tot groene pipeline
    • Kapotte code en langzame test suite
    • CI kan vaker falen dan lokaal (waar ligt de grens?)
  • Niets doen
    • Komt vaker voor dan je denkt
    • Moeilijk om tests te verwijderen

Problemen aanpakken

  • Quarantaine en oplossen
    • Test overslaan en eraan herinnerd worden
    • Tijdelijk minder coverage tot er tijd is om te fixen

CONCLUSIE

  • Zweven tussen de 4 oplossingen
  • Overleggen wat te doen met onbetrouwbare tests
  • Gewoonte kan erin roesten
     
  • Bitbucket deploys
  • Tests uitvoeren in random volgorde met seed nummer
  • Is de test onbetrouwbaar of lag het aan de environment?
  • Tests uitvoeren in continue loop in losse omgeving
  • Last resort: debug code om extra informatie te loggen
Made with Slides.com