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

The hitchhicker’s guide to unit testing

The hitchhicker’s guide to unit testing

You already know TDD, your code coverage is almost at 80%, jUnit has no secret for you? But you feel that you could do more with your tests, the tools you use have limitations. Or maybe you're just tired of assertEquals?

Don't panic! We will see how you can code tests. We will look upon:

- Mutation Testing
- BDD, Behaviour Driven Development
- Property Testing

Transcript

  1. The  hitchhicker’s   guide  to  unit  tes1ng   Rémy-­‐Christophe  Schermesser

      @el_picador  
  2. Ruby!   Scala!   Java!   Python!   PHP!  

  3. Ruby!   Scala!   Java!   Python!   PHP!  

    But  don’t  forget  your  towel  
  4. Test::Unit   ScalaTest   jUnit   uniFest   PHPUnit  

  5. Test::Unit   ScalaTest   jUnit   uniFest   PHPUnit  

    Again  don’t  forget  your  towel  
  6. JUnit  

  7. assertEquals   At  the  beginning,  we  had  

  8. Then   assertThatMyTestFitsOn OneLine(whatIExpect,   whatMyCodeIsDoing);  

  9. And   void  testWithCamelCase ToReadItBeFer()  {  ...  }  

  10. And  again   @Test   void  annotaZonsAreGood ForYourHealth()  {  ...

     }  
  11. And  again  again   void  testMyTest()  {      Obj

     obj  =  new  Obj();    //  10  lignes  of  things    assertEquals(…);   }  
  12. JUnit  

  13. JUnit   Mocks  

  14. JUnit   Fixtures   Mocks  

  15. JUnit   Behavior   tes1ng   with   RSpec  

  16. Problem   void  testMyTest()  {      Obj  obj  =

     new  Obj();    //  10  lignes  of  things    assertEquals(…);   }  
  17. Behavior  tesZng,  don’t  test,  do  describe   Describe  what  

    your  program   should  do  
  18. One  test   One  (english)   sentence   Behavior  tesZng,

     don’t  test,  do  describe  
  19. RSpec,  don’t  panic,   factorize  and  do  DSL  

  20. describe  CompaniesController  do        describe  "POST  create"  do

                 context  "when  recruiter     signed_in  with  no  company"  do                    …              end        end   end  
  21. describe  CompaniesController  do        describe  "POST  create"  do

                 context  "when  recruiter     signed_in  with  no  company"  do                    …              end        end   end  
  22. describe  CompaniesController  do        describe  "POST  create"  do

                 context  "when  recruiter     signed_in  with  no  company  an  email  is   sent"  do                    …              end        end   end  
  23. let!(:recruiter)  {  login_recruiter  create(:recruiter,            

         company_id:  nil)  }       context  "when  good  params"  do    let(:params)  {  …  }          it  {  expect  {  post  :create,  params  }.to  change(Company,  :count).by  1  }      it  {  expect  {  post  :create,  params  }.to          change(Ac1onMailer::Base.deliveries,  :count).by  2  }     end   “When  recruiter  signed_in  with  no  company”
  24. let!(:recruiter)  {  login_recruiter  create(:recruiter,  company_id:  nil)  }      

    context  "when  good  params"  do    let(:params)  {  …  }          it  {  expect  {  post  :create,  params  }.to  change(Company,  :count).by  1  }      it  {  expect  {  post  :create,  params  }.to          change(Ac1onMailer::Base.deliveries,  :count).by  2  }     end   “When  recruiter  signed_in  with  no  company”
  25. let!(:recruiter)  {  login_recruiter  create(:recruiter,  company_id:  nil)  }      

    context  "when  good  params"  do    let(:params)  {  …  }          it  {  expect  {  post  :create,  params  }.to  change(Company,  :count).by  1  }      it  {  expect  {  post  :create,  params  }.to          change(Ac1onMailer::Base.deliveries,  :count).by  2  }     end   “When  recruiter  signed_in  with  no  company”
  26. let!(:recruiter)  {  login_recruiter  create(:recruiter,  company_id:  nil)  }      

    context  "when  good  params"  do    let(:params)  {  …  }          it  {  expect  {  post  :create,  params  }.to                  change(Company,  :count).by  1  }      it  {  expect  {  post  :create,  params  }.to              change(Ac1onMailer::Base.deliveries,  :count).by  2  }     end   “When  recruiter  signed_in  with  no  company”
  27. Like  a  towel,  use  it  every  day  

  28. JUnit   Muta1on   tes1ng   Behavior   tes1ng  

    with   Javalanche  
  29. Code  coverage   has  limits   Code:  ctrl+c   Test:

     ctrl+v  
  30. Code  a  class  and  test  it  

  31. Mutate  it  

  32. &&   ++   !=   >   …  

    ||   -­‐-­‐   ==   <   …   Mutate  it  
  33. if(a  &&  b)  {          i++;  

    }  else  {          i-­‐-­‐;   }   if(a || b) { i++; } else { i--; } if(a && b) { i--; } else { i--; } Mutate  it  
  34. Kill  it  

  35. mvn  test   ant  -­‐f  javalanche.xml  mutaZonTest   Kill  it

     
  36. Run  tests   Green  tests   Something’s   wrong  

  37. Run  tests   Red  tests   Great  job!  

  38. Coverage  data   Equivalent  mutant   if(index  >=  10)  break

      and   if(index  ==  10)  break   Selec1ve  muta1on   Parallel  execu1on   Choose  your  mutants  wisely   Using  code  coverage  to   reduce  the  tests  to  run   Speed-­‐up   The  right  tool  
  39. None
  40. None
  41. Behavior   tes1ng   JUnit   Property   tes1ng  

    Muta1on   tes1ng   with   ScalaCheck  
  42. How  to  test  string   concatenaZon  ?   assert(  ("ta"

     +  "a")  ==  "taa"  )  
  43. How  to  test  string   concatenaZon  ?   assert(  ("ta"

     +  "a")  ==  "taa"  )   assert(  ("ta"  +  "b")  ==  "tab"  )  
  44. How  to  test  string   concatenaZon  ?   assert(  ("ta"

     +  "a")  ==  "taa"  )   assert(  ("ta"  +  "b")  ==  "tab"  )   …  
  45. How  to  test  string   concatenaZon  ?   assert(  ("ta"

     +  "a")  ==  "taa"  )   assert(  ("ta"  +  "b")  ==  "tab"  )   assert(  ("ta"  +  "z")  ==  "taz"  )   …  
  46. How  to  test  string   concatenaZon  ?   assert(  ("ta"

     +  "a")  ==  "taa"  )   assert(  ("ta"  +  "b")  ==  "tab"  )   assert(  ("ta"  +  "z")  ==  "taz"  )   …   But  boring  
  47. ∀n∈N,  ∃!k∈N   (n  =  2k  ⋁  n  =  2k+1)

      Remember  math  class?   ∀n,  n  =  42  
  48. val  n:  Int   val  k:  Int     (n

     ==  2k  ||  n  ==  2k  +  1)  ==  true   (n  %  2    ==  0  ||  n  %  2  ==  1)  ==  true     In  code  
  49. val  a:  String   val  b:  String     ((a+b)

     endsWith  b)    ==  true   ((a+b)  startsWith  a)    ==  true     (a+b).length  ==  a.length  +  b.length   String   concatenaZon   properZes  
  50. List[Int]  =>  isPalindrome(list)     (list.reverse  ==  list)  ==>  isPalindrome(list)

        (list.reverse  !=  list)  ==>  !isPalindrome(list)   Limits  
  51. None
  52. Behavior  tesZng        Every  day   MutaZon  tesZng

           CriZcal  code   Property  tesZng    à    CriZcal  code   Share  and  Enjoy  
  53. So  Long,  and   Thanks  for  All   the  Fish

      Rémy-­‐Christophe  Schermesser   @el_picador  
  54. Rémy-­‐Christophe  Schermesser   @el_picador   Behavior  tesZng   Rspec  (ruby)

      Jasmine  (javascript)     MutaZon  tesZng   Javalanche  (java)   Mutant  (ruby)   Property  tesZng   ScalaCheck  (scala)   QuickCheck  (haskell)   MrProper  (ruby)