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

More Decks by Rémy-Christophe Schermesser

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  3. Ruby!  
    Scala!  
    Java!  
    Python!  
    PHP!  
    But  don’t  forget  your  towel  

    View Slide

  4. Test::Unit  
    ScalaTest  
    jUnit  
    uniFest  
    PHPUnit  

    View Slide

  5. Test::Unit  
    ScalaTest  
    jUnit  
    uniFest  
    PHPUnit  
    Again  don’t  forget  your  towel  

    View Slide

  6. JUnit
     

    View Slide

  7. assertEquals  
    At  the  beginning,  we  had  

    View Slide

  8. Then  
    assertThatMyTestFitsOn
    OneLine(whatIExpect,  
    whatMyCodeIsDoing);  

    View Slide

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

    View Slide

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

    View Slide

  11. And  again  again  
    void  testMyTest()  {    
     Obj  obj  =  new  Obj();  
     //  10  lignes  of  things  
     assertEquals(…);  
    }  

    View Slide

  12. JUnit
     

    View Slide

  13. JUnit
     
    Mocks
     

    View Slide

  14. JUnit
     
    Fixtures
     
    Mocks
     

    View Slide

  15. JUnit
     
    Behavior
     
    tes1ng
     
    with
     
    RSpec
     

    View Slide

  16. Problem  
    void  testMyTest()  {    
     Obj  obj  =  new  Obj();  
     //  10  lignes  of  things  
     assertEquals(…);  
    }  

    View Slide

  17. Behavior  tesZng,  don’t  test,  do  describe
     
    Describe  what  
    your  program  
    should  do  

    View Slide

  18. One  test  
    One  (english)  
    sentence  
    Behavior  tesZng,  don’t  test,  do  describe
     

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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”

    View Slide

  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”

    View Slide

  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”

    View Slide

  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”

    View Slide

  27. Like  a  towel,  use  it  every  day  

    View Slide

  28. JUnit
     
    Muta1on  
    tes1ng
     
    Behavior
     
    tes1ng
     
    with
     
    Javalanche
     

    View Slide

  29. Code  coverage  
    has  limits
     
    Code:  ctrl+c
     
    Test:  ctrl+v
     

    View Slide

  30. Code  a  class  and  test  it  

    View Slide

  31. Mutate  it  

    View Slide

  32. &&
     
    ++
     
    !=
     
    >
     

     
    ||
     
    -­‐-­‐
     
    ==
     
    <
     

     
    Mutate  it  

    View Slide

  33. if(a  &&  b)  {  
           i++;  
    }  else  {  
           i-­‐-­‐;  
    }  
    if(a || b) {

    i++;

    } else {

    i--;

    }

    if(a && b) {

    i--;

    } else {

    i--;

    }

    Mutate  it  

    View Slide

  34. Kill  it  

    View Slide

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

    View Slide

  36. Run  tests  
    Green  tests  
    Something’s  
    wrong  

    View Slide

  37. Run  tests  
    Red  tests  
    Great  job!  

    View Slide

  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  

    View Slide

  39. View Slide

  40. View Slide

  41. Behavior
     
    tes1ng
     
    JUnit
     
    Property  
    tes1ng
      Muta1on  
    tes1ng
     
    with
     
    ScalaCheck
     

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  47. ∀n∈N,  ∃!k∈N  
    (n  =  2k  ⋁  n  =  2k+1)  
    Remember  math  class?  
    ∀n,  n  =  42  

    View Slide

  48. val  n:  Int  
    val  k:  Int  
     
    (n  ==  2k  ||  n  ==  2k  +  1)  ==  true  
    (n  %  2    ==  0  ||  n  %  2  ==  1)  ==  true  
     
    In  code  

    View Slide

  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  

    View Slide

  50. List[Int]  =>  isPalindrome(list)  
     
    (list.reverse  ==  list)  ==>  isPalindrome(list)  
     
    (list.reverse  !=  list)  ==>  !isPalindrome(list)  
    Limits  

    View Slide

  51. View Slide

  52. Behavior  tesZng        Every  day  
    MutaZon  tesZng        CriZcal  code  
    Property  tesZng    à    CriZcal  code  
    Share  and  Enjoy  

    View Slide

  53. So  Long,  and  
    Thanks  for  All  
    the  Fish  
    Rémy-­‐Christophe  Schermesser  
    @el_picador  

    View Slide

  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)  

    View Slide