SlideShare une entreprise Scribd logo
1  sur  50
Télécharger pour lire hors ligne
Test-Driven Development
Fundamentals on Force.com:
Step-by-Step Bowling Kata
Developer Track
Kyle Thornton, Mavens Consulting @knthornt
Sean Harrison, Mavens Consulting @GizmoForce
Safe Harbor
 Safe harbor statement under the Private Securities Litigation Reform Act of 1995:

 This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of
 the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking
 statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service
 availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future
 operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of
 our services.

 The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service,
 new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions
 or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other litigation, risks associated with possible mergers
 and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees
 and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and
 utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is
 included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This documents and others containing important disclosures
 are available on the SEC Filings section of the Investor Information section of our Web site.

 Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not be
 delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available.
 Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
Photo   by   Metro-Goldwyn-Mayer   (MGM)   –   ©   1996   -   MGM/UA
Test-Driven Development

 Write your tests before your write your code


 Learn by doing


 Kata = step-by-step example
Test-Driven Development

 Classic Bowling Example
   3 of the 5 tests today
   4 and 5 online
   Provide code for you to finish


                                      Credit where credit is due
                                        – 2005 version of kata
                                        – ObjectMentor.com
This is not ‘Nam. This is Bowling. There are Rules.




10 Frames / 2 rolls each                       10th Frame
Each frame has a score                              rolls as needed
Frame score = pins down with rolls + bonuses        max rolls = 3

Bonuses:
   Spare = 2 Rolls + 1 bonus roll
   Strike = 1 Roll + 2 bonus rolls
Game           Frame          Roll
roll(Integer)   score()       roll(Integer)
score()




                 TenthFrame
                score()
Assumptions

 1. We are only calculating the score
 2. The class we build will be for one bowler
 3. We are not responsible for the input of the scores in this
    class
 4. There would be a complimentary class to handle the score
    input
Let’s Define Our Use Cases

 1. Score should be 0 if bowler rolls a complete gutter game
 2. Score should be 20 if bowler knocks down 1 pin every roll
 3. Score calculates properly if bowler rolls a spare
 4. Score calculates properly if bowler rolls a strike
 5. Score is 300 if bowler rolls a perfect game
The First Test
@isTest
private class BowlingGameTest {

    static testMethod void testGutterGame() {
       Game g = new Game();
    }
}
The First Test
@isTest                                         public with sharing class Game {
private class BowlingGameTest {
                                                }
    static testMethod void testGutterGame() {
       Game g = new Game();
    }
}
The First Test
@isTest                                         public with sharing class Game {
private class BowlingGameTest {
                                                }
    static testMethod void testGutterGame() {
       Game g = new Game();
    }
}
The First Test
@isTest                                         public with sharing class Game {
private class BowlingGameTest {
                                                }
    static testMethod void testGutterGame() {
       Game g = new Game();
    }
}
The First Test
@isTest                                         public with sharing class Game {
private class BowlingGameTest {
                                                }
    static testMethod void testGutterGame() {
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(0);
       }
    }
}
The First Test
@isTest                                         public with sharing class Game {
private class BowlingGameTest {                   public void roll(Integer pins) {
                                                  }
    static testMethod void testGutterGame() {   }
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(0);
       }
    }
}
The First Test
@isTest                                                                  public with sharing class Game {
private class BowlingGameTest {                                            public void roll(Integer pins) {
                                                                           }
    static testMethod void testGutterGame() {                            }
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(0);
       }
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }
}
The First Test
@isTest                                                                 public with sharing class Game {
private class BowlingGameTest {                                           public void roll(Integer pins) {
                                                                          }
    static testMethod void testGutterGame() {
       Game g = new Game();                                                 public Integer score() {
       for (Integer i=0; i<20; i++ ) {                                        return null;
          g.roll(0);                                                        }
       }                                                                }
       System.assertEquals(0,g.score() ‘Gutter game score not zero');
    }
}




                                                      Expected 0        but returned null
The First Test                                                           public with sharing class Game {
@isTest
private class BowlingGameTest {                                            public void roll(Integer pins) {
                                                                           }
    static testMethod void testGutterGame() {
       Game g = new Game();                                                  public Integer score() {
       for (Integer i=0; i<20; i++ ) {                                         return 0;
          g.roll(0);                                                         }
       }                                                                 }
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }
}
Unit Test #1 - Score should be 0 if bowler rolls a complete gutter game



                                 Game
                            public roll(Integer)
                              public score()




                            Next Use Case:

       Score should be 20 if bowler knocks down 1 pin every roll
The Second Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                public void roll(Integer pins) {
                                                                               }
    static testMethod void testGutterGame() {
       Game g = new Game();                                                      public Integer score() {
       for (Integer i=0; i<20; i++ ) {                                             return 0;
          g.roll(0);                                                             }
       }                                                                     }
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
• Game creation is duplicated
The Second Test
@isTest                                                                      public with sharing class Game {
                                                                                                                  • Roll loop is duplicated
private class BowlingGameTest {                                                public void roll(Integer pins) {
                                                                               }
    static testMethod void testGutterGame() {
       Game g = new Game();                                                      public Integer score() {
       for (Integer i=0; i<20; i++ ) {                                             return 0;
          g.roll(0);                                                             }
       }                                                                     }
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
• Game creation is duplicated
The Second Test
@isTest                                                                      public with sharing class Game {
                                                                                                                  • Roll loop is duplicated
private class BowlingGameTest {                                                public void roll(Integer pins) {
                                                                               }
    static testMethod void testGutterGame() {
       Game g = new Game();                                                      public Integer score() {
       for (Integer i=0; i<20; i++ ) {                                             return 0;
          g.roll(0);                                                             }
       }                                                                     }
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}




                                                       Expected 20 but returned 0
• Game creation is duplicated
The Second Test
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Roll loop is duplicated
private class BowlingGameTest {                                                private Integer score = 0;

    static testMethod void testGutterGame() {                                    public void roll(Integer pins) {
       Game g = new Game();                                                        score += pins;
       for (Integer i=0; i<20; i++ ) {                                           }
          g.roll(0);
       }                                                                         public Integer score() {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             return score;
    }                                                                            }
                                                                             }
    static testMethod void testAllOnes() {
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
Let’s Do Some Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Game creation is duplicated
                                                                                                                    • Roll loop is duplicated
private class BowlingGameTest {                                                private Integer score = 0;

    static testMethod void testGutterGame() {                                    public void roll(Integer pins) {
       Game g = new Game();                                                        score += pins;
       for (Integer i=0; i<20; i++ ) {                                           }
          g.roll(0);
       }                                                                         public Integer score() {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             return score;
    }                                                                            }
                                                                             }
    static testMethod void testAllOnes() {
       Game g = new Game();
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
Let’s Do Some Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Game creation is duplicated
                                                                                                                    • Roll loop is duplicated
private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    static testMethod void testGutterGame() {                                      score += pins;
       for (Integer i=0; i<20; i++ ) {                                           }
          g.roll(0);
       }                                                                         public Integer score() {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             return score;
    }                                                                            }
                                                                             }
    static testMethod void testAllOnes() {
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
Let’s Do Some Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Roll loop is duplicated

private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    static testMethod void testGutterGame() {                                      score += pins;
       Integer n = 20;                                                           }
       Integer pins = 0;
       for (Integer i=0; i<n; i++ ) {                                            public Integer score() {
          g.roll(pins);                                                            return score;
       }                                                                         }
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');       }
    }

    static testMethod void testAllOnes() {
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
Let’s Do Some Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Roll loop is duplicated

private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    private static void rollMany(Integer n, Integer pins) {                        score += pins;
        for (Integer i=0; i<n; i++) {                                            }
          g.roll(pins);
       }                                                                         public Integer score() {
    }                                                                              return score;
                                                                                 }
    static testMethod void testGutterGame() {                                }
       Integer n = 20;
       Integer pins = 0;
       rollMany(n, pins);
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
Let’s Do Some Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Roll loop is duplicated

private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    private static void rollMany(Integer n, Integer pins) {                        score += pins;
        for (Integer i=0; i<n; i++) {                                            }
          g.roll(pins);
       }                                                                         public Integer score() {
    }                                                                              return score;
                                                                                 }
    static testMethod void testGutterGame() {                                }
       rollMany(20, 0);
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       for (Integer i=0; i<20; i++ ) {
          g.roll(1);
       }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
Let’s Do Some Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Roll loop is duplicated

private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    private static void rollMany(Integer n, Integer pins) {                        score += pins;
        for (Integer i=0; i<n; i++) {                                            }
          g.roll(pins);
       }                                                                         public Integer score() {
    }                                                                              return score;
                                                                                 }
    static testMethod void testGutterGame() {                                }
       rollMany(20, 0);
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       rollMany(20, 1);
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }
}
Unit Test #2 - Score should be 20 if bowler knocks down 1 pin every roll


                               Game
                          Integer score

                          public roll(Integer)
                          public score()




                           Next Use Case:

   Score calculates properly if bowler rolls a spare
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    private static void rollMany(Integer n, Integer pins) {                        score += pins;
        for (Integer i=0; i<n; i++) {                                            }
          g.roll(pins);
       }                                                                         public Integer score() {
    }                                                                              return score;
                                                                                 }
    static testMethod void testGutterGame() {                                }
       rollMany(20, 0);
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       rollMany(20, 1);
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }

    static testMethod void testOneSpare() {
       g.roll(5);
       g.roll(5); //spare
       g.roll(3);
                                  Ugly comment
       rollMany(17,0);
       System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    private static void rollMany(Integer n, Integer pins) {                        score += pins;
        for (Integer i=0; i<n; i++) {                                            }
          g.roll(pins);
       }                                                                         public Integer score() {
    }                                                                              return score;
                                                                                 }
    static testMethod void testGutterGame() {                                }
       rollMany(20, 0);
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       rollMany(20, 1);
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }

    static testMethod void testOneSpare() {
       g.roll(5);
       g.roll(5); //spare
       g.roll(3);
       rollMany(17,0);                                   Expected 16 but returned 13
       System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                                                           Tempted to use flag to
                                                                                 public void roll(Integer pins) {          Remember previous roll.
    private static void rollMany(Integer n, Integer pins) {                        score += pins;                          Design must be wrong.
        for (Integer i=0; i<n; i++) {                                            }
          g.roll(pins);
       }                                                                         public Integer score() {              Roll() calculates score
    }                                                                              return score;
                                                                                 }
    static testMethod void testGutterGame() {                                }                                      score() does not calculate
       rollMany(20, 0);                                                                                             score, but name implies that it
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }
                                                                                                                    does.

    static testMethod void testAllOnes() {
       rollMany(20, 1);
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }                                                                              Design is not going in the right direction.
                                                                                   -Methods doing the wrong job
    static testMethod void testOneSpare() {
       g.roll(5);                                                                  -Going down a design path we would rather avoid
       g.roll(5); //spare
       g.roll(3);                                                                  Let’s comment out testOneSpare and do some
       rollMany(17,0);
       System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
                                                                                   rework
    }
}
The Third Test
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Ugly comment in test
private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();
                                                                                 public void roll(Integer pins) {
    private static void rollMany(Integer n, Integer pins) {                        score += pins;
        for (Integer i=0; i<n; i++) {                                            }
          g.roll(pins);
       }                                                                         public Integer score() {
    }                                                                              return score;
                                                                                 }
    static testMethod void testGutterGame() {                                }
       rollMany(20, 0);
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');
    }

    static testMethod void testAllOnes() {
       rollMany(20, 1);
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }

    // static testMethod void testOneSpare() {
    // g.roll(5);
    // g.roll(5); //spare
    // g.roll(3);
    // rollMany(17,0);
    // System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    //}
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();                                         private list<Integer> rolls =
                                                                                                 new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    private static void rollMany(Integer n, Integer pins) {                    private Integer currentRoll = 0;
        for (Integer i=0; i<n; i++) {
          g.roll(pins);                                                          public void roll(Integer pins) {
       }                                                                           score += pins;
    }                                                                              rolls[curentRoll++] = pins;
                                                                                 }
    static testMethod void testGutterGame() {
       rollMany(20, 0);                                                          public Integer score() {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             return score;
    }                                                                            }
                                                                             }
    static testMethod void testAllOnes() {
       rollMany(20, 1);
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }

    // static testMethod void testOneSpare() {
    // g.roll(5);
    // g.roll(5); //spare
    // g.roll(3);
    // rollMany(17,0);
    // System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    //}
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private Integer score = 0;
   private static Game g = new Game();                                         private list<Integer> rolls =
                                                                                                 new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    private static void rollMany(Integer n, Integer pins) {                    private Integer currentRoll = 0;
        for (Integer i=0; i<n; i++) {
          g.roll(pins);                                                          public void roll(Integer pins) {
       }                                                                           score += pins;
    }                                                                              rolls[curentRoll++] = pins;
                                                                                 }
    static testMethod void testGutterGame() {
       rollMany(20, 0);                                                          public Integer score() {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             Integer score = 0;
    }                                                                              for (Integer i=0, i<rolls.length; i++) {
                                                                                      score += rolls[i];
    static testMethod void testAllOnes() {                                         }
       rollMany(20, 1);                                                            return score;
       System.assertEquals(20,g.score(), 'An all ones game score not 20');       }
    }                                                                        }

    // static testMethod void testOneSpare() {
    // g.roll(5);
    // g.roll(5); //spare
    // g.roll(3);
    // rollMany(17,0);
    // System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    //}
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;
       rollMany(20, 0);                                                            for (Integer i=0, i<rolls.length; i++) {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');                score += rolls[i];
    }                                                                              }
                                                                                   return score;
    static testMethod void testAllOnes() {                                       }
       rollMany(20, 1);                                                      }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }

    // static testMethod void testOneSpare() {
    // g.roll(5);
    // g.roll(5); //spare
    // g.roll(3);
    // rollMany(17,0);
    // System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    //}
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;
       rollMany(20, 0);                                                            for (Integer i=0, i<rolls.length; i++) {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');                score += rolls[i];
    }                                                                              }
                                                                                   return score;
    static testMethod void testAllOnes() {                                       }
       rollMany(20, 1);                                                      }
       System.assertEquals(20,g.score(), 'An all ones game score not 20');
    }

    static testMethod void testOneSpare() {
       g.roll(5);
       g.roll(5); //spare
       g.roll(3);
       rollMany(17,0);                                        Expected 16 but returned 13
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                          public void roll(Integer pins) {
          g.roll(pins);                                                          rolls[curentRoll++] = pins;
       }                                                                       }
    }
                                                                               public Integer score() {
    static testMethod void testGutterGame() {                                    Integer score = 0;
       rollMany(20, 0);                                                          for (Integer i=0, i<rolls.length; i++) {
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');              if (rolls[i] + rolls[i+1] == 10) { //spare
    }                                                                                   score+=…..
                                                                                    }
    static testMethod void testAllOnes() {                                          score += rolls[i];
       rollMany(20, 1);                                                          }
                                                                                                                  This isn’t going to work because I
       System.assertEquals(20,g.score(), 'An all ones game score not 20');       return score;
                                                                                                                  might not refer to the first ball of the
    }                                                                          }
                                                                             }                                    frame.
    static testMethod void testOneSpare() {
       g.roll(5);                                                                                                 Design is still wrong.
       g.roll(5); //spare
       g.roll(3);                                                                                                 Need to walk through array one
       rollMany(17,0);                                                                                            frame (two balls) at a time.
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;
       rollMany(20, 0);                                                            Integer i = 0;
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             for (Integer frame=0, frame<10; frame++) {
    }                                                                                 score += rolls[i] + rolls[i+1];
                                                                                      i+=2;
    static testMethod void testAllOnes() {                                         }
       rollMany(20, 1);                                                            return score;
       System.assertEquals(20,g.score(), 'An all ones game score not 20');       }
    }                                                                        }

    // static testMethod void testOneSpare() {
    // g.roll(5);
    // g.roll(5); //spare
    // g.roll(3);
    // rollMany(17,0);
    // System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    //}
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;
       rollMany(20, 0);                                                            Integer i = 0;
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             for (Integer frame=0, frame<10; frame++) {
    }                                                                                 score += rolls[i] + rolls[i+1];
                                                                                      i+=2;
    static testMethod void testAllOnes() {                                         }
       rollMany(20, 1);                                                            return score;
       System.assertEquals(20,g.score(), 'An all ones game score not 20');       }
    }                                                                        }

    static testMethod void testOneSpare() {
       g.roll(5);
       g.roll(5); //spare
       g.roll(3);                                         Expected 16 but returned 13
       rollMany(17,0);
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
The Third Test
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;
       rollMany(20, 0);                                                            Integer i = 0;
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             for (Integer frame=0, frame<10; frame++) {
    }                                                                                 if (rolls[i] + rolls[i+1] == 10) { //spare
                                                                                          score += 10 + rolls[i+2];
    static testMethod void testAllOnes() {                                                i += 2;
       rollMany(20, 1);                                                               } else {
       System.assertEquals(20,g.score(), 'An all ones game score not 20');                score += rolls[i] + rolls[i+1];
    }                                                                                     i+=2;
                                                                                      }
    static testMethod void testOneSpare() {                                        }
       g.roll(5);                                                                  return score;
       g.roll(5); //spare                                                        }
       g.roll(3);                                                            }
       rollMany(17,0);
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
Some More Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                    • Ugly comment in conditional
private class BowlingGameTest {                                                private list<Integer> rolls =        • i is a bad variable name
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;                    Bad variable name
       rollMany(20, 0);                                                            Integer i = 0;
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             for (Integer frame=0, frame<10; frame++) {
    }                                                                                 if (rolls[i] + rolls[i+1] == 10) { //spare
                                                                                          score += 10 + rolls[i+2];
    static testMethod void testAllOnes() {                                                i += 2;
       rollMany(20, 1);                                                               } else {                                    Ugly Comment
       System.assertEquals(20,g.score(), 'An all ones game score not 20');                score += rolls[i] + rolls[i+1];
    }                                                                                     i+=2;
                                                                                      }
    static testMethod void testOneSpare() {                                        }
       g.roll(5);                                                                  return score;
       g.roll(5); //spare                                                        }
       g.roll(3);                                                            }
       rollMany(17,0);
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
Some More Clean-up
@isTest                                                                      public with sharing class Game {
                                                                                                                      • Ugly comment in conditional
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;
       rollMany(20, 0);                                                            Integer rollsIndex = 0;
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             for (Integer frame=0, frame<10; frame++) {
    }                                                                                 if ( rolls[rollsIndex] + rolls[rollsIndex+1]) { //spare
                                                                                          score += 10 + rolls[i+2];
    static testMethod void testAllOnes() {                                                rollsIndex += 2;
       rollMany(20, 1);                                                               } else {
       System.assertEquals(20,g.score(), 'An all ones game score not 20');                score += rolls[rollsIndex] + rolls[rollsIndex+1];
    }                                                                                     rollsIndex+=2;
                                                                                      }
    static testMethod void testOneSpare() {                                        }
       g.roll(5);                                                                  return score;
       g.roll(5); //spare                                                        }
       g.roll(3);                                                            }
       rollMany(17,0);
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);
    }
}
• Ugly comment in test
Some More Clean-up
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                                                                               private Integer currentRoll = 0;
    private static void rollMany(Integer n, Integer pins) {
        for (Integer i=0; i<n; i++) {                                            public void roll(Integer pins) {
          g.roll(pins);                                                            rolls[curentRoll++] = pins;
       }                                                                         }
    }
                                                                                 public Integer score() {
    static testMethod void testGutterGame() {                                      Integer score = 0;
       rollMany(20, 0);                                                            Integer rollsIndex = 0;
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');             for (Integer frame=0, frame<10; frame++) {
    }                                                                                 if ( isSpare(rollsIndex)) {
                                                                                          score += 10 + rolls[i+2];
    static testMethod void testAllOnes() {                                                rollsIndex += 2;
       rollMany(20, 1);                                                               } else {
       System.assertEquals(20,g.score(), 'An all ones game score not 20');                score += rolls[rollsIndex] + rolls[rollsIndex+1];
    }                                                                                     rollsIndex+=2;
                                                                                      }
    static testMethod void testOneSpare() {                                        }
       g.roll(5);                                                                  return score;
       g.roll(5); //spare                                                        }
       g.roll(3);
       rollMany(17,0);                                                           private Boolean isSpare(Integer rollsIndex) {
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);              return rolls[rollsIndex] + rolls[rollsIndex+1] == 10;
    }                                                                            }
}                                                                            }
Some More Clean-up
@isTest                                                                      public with sharing class Game {
private class BowlingGameTest {                                                private list<Integer> rolls =
   private static Game g = new Game();                                                           new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
   ……..                                                                        private Integer currentRoll = 0;

    static testMethod void testGutterGame() {                                    public void roll(Integer pins) {
       rollMany(20, 0);                                                            rolls[curentRoll++] = pins;
       System.assertEquals(0,g.score(), ‘Gutter game score not zero');           }
    }
                                                                                 public Integer score() {
    static testMethod void testAllOnes() {                                         Integer score = 0;
       rollMany(20, 1);                                                            Integer rollsIndex = 0;
       System.assertEquals(20,g.score(), 'An all ones game score not 20');         for (Integer frame=0, frame<10; frame++) {
    }                                                                                 if ( isSpare(rollsIndex)) {
                                                                                          score += 10 + rolls[i+2];
    static testMethod void testOneSpare() {                                               rollsIndex += 2;
       rollSpare();                                                                   } else {
       g.roll(3);                                                                         score += rolls[rollsIndex] + rolls[rollsIndex+1];
       rollMany(17,0);                                                                    rollsIndex+=2;
      System.assertEquals(16,g.score(), ‘Spare not scored correctly’);                }
    }                                                                              }
                                                                                   return score;
    private static void rollSpare() {                                            }
       g.roll(5);
       g.roll(5);                                                                private Boolean isSpare(Integer rollsIndex) {
    }                                                                               return rolls[rollsIndex] + rolls[rollsIndex+1] == 10;
}                                                                                }
                                                                             }
Unit Test #3 – Score calculates properly if bowler rolls a spare


                            Game
                       List rolls
                       Integer currentRoll
                       public roll(Integer)
                       public score()

                       isSpare(Integer)




                       Next Use Case:

Score calculates properly if bowler rolls a strike
What Have We Seen?

A disciplined test-driven approach means…
 …Clean, more readable code
 …Refining our design as we go
 …Quicker feedback
 …Regression testing becomes trivial
Follow-up

 You finish the app with the following:
   https://github.com/knthornt/Dreamforce-2012---TDD-Session
   Complete Slide Deck (with tests 4 & 5)
   Tests 1 – 3 package
   Fully baked version


 Completed kata video
   http://bit.ly/U9dKa8
Thank You!

Kyle Thornton, Mavens Consulting @knthornt
Sean Harrison, Mavens Consulting @GizmoForce



                                      Mavens

Mav e ns C on su lt in g . c om     info@m av en s . i o   312. 7 25. 8 52 8

Contenu connexe

Tendances

The Ring programming language version 1.5.2 book - Part 67 of 181
The Ring programming language version 1.5.2 book - Part 67 of 181The Ring programming language version 1.5.2 book - Part 67 of 181
The Ring programming language version 1.5.2 book - Part 67 of 181Mahmoud Samir Fayed
 
The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196Mahmoud Samir Fayed
 
Insertion sort
Insertion sortInsertion sort
Insertion sortRajendran
 
The Ring programming language version 1.5.1 book - Part 49 of 180
The Ring programming language version 1.5.1 book - Part 49 of 180The Ring programming language version 1.5.1 book - Part 49 of 180
The Ring programming language version 1.5.1 book - Part 49 of 180Mahmoud Samir Fayed
 
Ch 1 part-1 final
Ch 1 part-1 finalCh 1 part-1 final
Ch 1 part-1 finalaminsir
 
The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189Mahmoud Samir Fayed
 
Lecture 2
Lecture 2Lecture 2
Lecture 2sajinsc
 
생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트기룡 남
 
The Ring programming language version 1.2 book - Part 39 of 84
The Ring programming language version 1.2 book - Part 39 of 84The Ring programming language version 1.2 book - Part 39 of 84
The Ring programming language version 1.2 book - Part 39 of 84Mahmoud Samir Fayed
 

Tendances (12)

The Ring programming language version 1.5.2 book - Part 67 of 181
The Ring programming language version 1.5.2 book - Part 67 of 181The Ring programming language version 1.5.2 book - Part 67 of 181
The Ring programming language version 1.5.2 book - Part 67 of 181
 
The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196The Ring programming language version 1.7 book - Part 57 of 196
The Ring programming language version 1.7 book - Part 57 of 196
 
Insertion sort
Insertion sortInsertion sort
Insertion sort
 
662305 LAB13
662305 LAB13662305 LAB13
662305 LAB13
 
The Ring programming language version 1.5.1 book - Part 49 of 180
The Ring programming language version 1.5.1 book - Part 49 of 180The Ring programming language version 1.5.1 book - Part 49 of 180
The Ring programming language version 1.5.1 book - Part 49 of 180
 
Ch 1 part-1 final
Ch 1 part-1 finalCh 1 part-1 final
Ch 1 part-1 final
 
The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189The Ring programming language version 1.6 book - Part 62 of 189
The Ring programming language version 1.6 book - Part 62 of 189
 
08 - Complexity
08 - Complexity08 - Complexity
08 - Complexity
 
Lecture 2
Lecture 2Lecture 2
Lecture 2
 
생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트
 
Javascript quiz
Javascript quizJavascript quiz
Javascript quiz
 
The Ring programming language version 1.2 book - Part 39 of 84
The Ring programming language version 1.2 book - Part 39 of 84The Ring programming language version 1.2 book - Part 39 of 84
The Ring programming language version 1.2 book - Part 39 of 84
 

En vedette

Why Test Driven Development?
Why Test Driven Development?Why Test Driven Development?
Why Test Driven Development?Naresh Jain
 
Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...
Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...
Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...agil8 Ltd
 
Test Driven Development (TDD) - CVCC 2011
Test Driven Development (TDD) - CVCC 2011Test Driven Development (TDD) - CVCC 2011
Test Driven Development (TDD) - CVCC 2011Tom Steele
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Developmentroelofr
 
Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014
Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014
Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014agil8 Ltd
 
Test driven development
Test driven developmentTest driven development
Test driven developmentShalabh Saxena
 
Refactoring legacy code driven by tests - ITA
Refactoring legacy code driven by tests -  ITARefactoring legacy code driven by tests -  ITA
Refactoring legacy code driven by tests - ITALuca Minudel
 

En vedette (10)

Test driven development
Test driven developmentTest driven development
Test driven development
 
Why Test Driven Development?
Why Test Driven Development?Why Test Driven Development?
Why Test Driven Development?
 
Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...
Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...
Agile Software Development and Test Driven Development: Agil8's Dave Putman 3...
 
Tdd by exam 2
Tdd by exam 2Tdd by exam 2
Tdd by exam 2
 
usability testing
usability testingusability testing
usability testing
 
Test Driven Development (TDD) - CVCC 2011
Test Driven Development (TDD) - CVCC 2011Test Driven Development (TDD) - CVCC 2011
Test Driven Development (TDD) - CVCC 2011
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
 
Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014
Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014
Agil8 Agile Story Writing - Impact Mapping - David Hicks - 30 Oct 2014
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
Refactoring legacy code driven by tests - ITA
Refactoring legacy code driven by tests -  ITARefactoring legacy code driven by tests -  ITA
Refactoring legacy code driven by tests - ITA
 

Similaire à Test-Driven Development Fundamentals on Force.com

Bowling game kata
Bowling game kataBowling game kata
Bowling game kataJoe McCall
 
Bowling game kata
Bowling game kataBowling game kata
Bowling game kataRahman Ash
 
Bowling game kata
Bowling game kataBowling game kata
Bowling game kataCarol Bruno
 
The main class of the tictoe game looks like.public class Main {.pdf
The main class of the tictoe game looks like.public class Main {.pdfThe main class of the tictoe game looks like.public class Main {.pdf
The main class of the tictoe game looks like.public class Main {.pdfasif1401
 
package com.tictactoe; public class Main {public void play() {.pdf
package com.tictactoe; public class Main {public void play() {.pdfpackage com.tictactoe; public class Main {public void play() {.pdf
package com.tictactoe; public class Main {public void play() {.pdfinfo430661
 

Similaire à Test-Driven Development Fundamentals on Force.com (6)

Bowling game kata
Bowling game kataBowling game kata
Bowling game kata
 
Bowling game kata
Bowling game kataBowling game kata
Bowling game kata
 
Bowling game kata
Bowling game kataBowling game kata
Bowling game kata
 
The main class of the tictoe game looks like.public class Main {.pdf
The main class of the tictoe game looks like.public class Main {.pdfThe main class of the tictoe game looks like.public class Main {.pdf
The main class of the tictoe game looks like.public class Main {.pdf
 
Property-based testing
Property-based testingProperty-based testing
Property-based testing
 
package com.tictactoe; public class Main {public void play() {.pdf
package com.tictactoe; public class Main {public void play() {.pdfpackage com.tictactoe; public class Main {public void play() {.pdf
package com.tictactoe; public class Main {public void play() {.pdf
 

Plus de Salesforce Developers

Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSalesforce Developers
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceSalesforce Developers
 
Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base ComponentsSalesforce Developers
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsSalesforce Developers
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaSalesforce Developers
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentSalesforce Developers
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsSalesforce Developers
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsSalesforce Developers
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsSalesforce Developers
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and TestingSalesforce Developers
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilitySalesforce Developers
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce dataSalesforce Developers
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionSalesforce Developers
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPSalesforce Developers
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceSalesforce Developers
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureSalesforce Developers
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DXSalesforce Developers
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectSalesforce Developers
 

Plus de Salesforce Developers (20)

Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component Performance
 
Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base Components
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer Highlights
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX India
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local Development
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web Components
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web Components
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer Highlights
 
Live coding with LWC
Live coding with LWCLive coding with LWC
Live coding with LWC
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and Testing
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura Interoperability
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce data
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An Introduction
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCP
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in Salesforce
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data Capture
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DX
 
Get Into Lightning Flow Development
Get Into Lightning Flow DevelopmentGet Into Lightning Flow Development
Get Into Lightning Flow Development
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS Connect
 

Test-Driven Development Fundamentals on Force.com

  • 1. Test-Driven Development Fundamentals on Force.com: Step-by-Step Bowling Kata Developer Track Kyle Thornton, Mavens Consulting @knthornt Sean Harrison, Mavens Consulting @GizmoForce
  • 2. Safe Harbor Safe harbor statement under the Private Securities Litigation Reform Act of 1995: This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services. The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other litigation, risks associated with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This documents and others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site. Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
  • 3. Photo by Metro-Goldwyn-Mayer (MGM) – © 1996 - MGM/UA
  • 4. Test-Driven Development Write your tests before your write your code Learn by doing Kata = step-by-step example
  • 5. Test-Driven Development Classic Bowling Example  3 of the 5 tests today  4 and 5 online  Provide code for you to finish  Credit where credit is due – 2005 version of kata – ObjectMentor.com
  • 6. This is not ‘Nam. This is Bowling. There are Rules. 10 Frames / 2 rolls each 10th Frame Each frame has a score rolls as needed Frame score = pins down with rolls + bonuses max rolls = 3 Bonuses: Spare = 2 Rolls + 1 bonus roll Strike = 1 Roll + 2 bonus rolls
  • 7. Game Frame Roll roll(Integer) score() roll(Integer) score() TenthFrame score()
  • 8. Assumptions 1. We are only calculating the score 2. The class we build will be for one bowler 3. We are not responsible for the input of the scores in this class 4. There would be a complimentary class to handle the score input
  • 9. Let’s Define Our Use Cases 1. Score should be 0 if bowler rolls a complete gutter game 2. Score should be 20 if bowler knocks down 1 pin every roll 3. Score calculates properly if bowler rolls a spare 4. Score calculates properly if bowler rolls a strike 5. Score is 300 if bowler rolls a perfect game
  • 10. The First Test @isTest private class BowlingGameTest { static testMethod void testGutterGame() { Game g = new Game(); } }
  • 11. The First Test @isTest public with sharing class Game { private class BowlingGameTest { } static testMethod void testGutterGame() { Game g = new Game(); } }
  • 12. The First Test @isTest public with sharing class Game { private class BowlingGameTest { } static testMethod void testGutterGame() { Game g = new Game(); } }
  • 13. The First Test @isTest public with sharing class Game { private class BowlingGameTest { } static testMethod void testGutterGame() { Game g = new Game(); } }
  • 14. The First Test @isTest public with sharing class Game { private class BowlingGameTest { } static testMethod void testGutterGame() { Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(0); } } }
  • 15. The First Test @isTest public with sharing class Game { private class BowlingGameTest { public void roll(Integer pins) { } static testMethod void testGutterGame() { } Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(0); } } }
  • 16. The First Test @isTest public with sharing class Game { private class BowlingGameTest { public void roll(Integer pins) { } static testMethod void testGutterGame() { } Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(0); } System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } }
  • 17. The First Test @isTest public with sharing class Game { private class BowlingGameTest { public void roll(Integer pins) { } static testMethod void testGutterGame() { Game g = new Game(); public Integer score() { for (Integer i=0; i<20; i++ ) { return null; g.roll(0); } } } System.assertEquals(0,g.score() ‘Gutter game score not zero'); } } Expected 0 but returned null
  • 18. The First Test public with sharing class Game { @isTest private class BowlingGameTest { public void roll(Integer pins) { } static testMethod void testGutterGame() { Game g = new Game(); public Integer score() { for (Integer i=0; i<20; i++ ) { return 0; g.roll(0); } } } System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } }
  • 19. Unit Test #1 - Score should be 0 if bowler rolls a complete gutter game Game public roll(Integer) public score() Next Use Case: Score should be 20 if bowler knocks down 1 pin every roll
  • 20. The Second Test @isTest public with sharing class Game { private class BowlingGameTest { public void roll(Integer pins) { } static testMethod void testGutterGame() { Game g = new Game(); public Integer score() { for (Integer i=0; i<20; i++ ) { return 0; g.roll(0); } } } System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 21. • Game creation is duplicated The Second Test @isTest public with sharing class Game { • Roll loop is duplicated private class BowlingGameTest { public void roll(Integer pins) { } static testMethod void testGutterGame() { Game g = new Game(); public Integer score() { for (Integer i=0; i<20; i++ ) { return 0; g.roll(0); } } } System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 22. • Game creation is duplicated The Second Test @isTest public with sharing class Game { • Roll loop is duplicated private class BowlingGameTest { public void roll(Integer pins) { } static testMethod void testGutterGame() { Game g = new Game(); public Integer score() { for (Integer i=0; i<20; i++ ) { return 0; g.roll(0); } } } System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } } Expected 20 but returned 0
  • 23. • Game creation is duplicated The Second Test @isTest public with sharing class Game { • Roll loop is duplicated private class BowlingGameTest { private Integer score = 0; static testMethod void testGutterGame() { public void roll(Integer pins) { Game g = new Game(); score += pins; for (Integer i=0; i<20; i++ ) { } g.roll(0); } public Integer score() { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); return score; } } } static testMethod void testAllOnes() { Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 24. Let’s Do Some Clean-up @isTest public with sharing class Game { • Game creation is duplicated • Roll loop is duplicated private class BowlingGameTest { private Integer score = 0; static testMethod void testGutterGame() { public void roll(Integer pins) { Game g = new Game(); score += pins; for (Integer i=0; i<20; i++ ) { } g.roll(0); } public Integer score() { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); return score; } } } static testMethod void testAllOnes() { Game g = new Game(); for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 25. Let’s Do Some Clean-up @isTest public with sharing class Game { • Game creation is duplicated • Roll loop is duplicated private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { static testMethod void testGutterGame() { score += pins; for (Integer i=0; i<20; i++ ) { } g.roll(0); } public Integer score() { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); return score; } } } static testMethod void testAllOnes() { for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 26. Let’s Do Some Clean-up @isTest public with sharing class Game { • Roll loop is duplicated private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { static testMethod void testGutterGame() { score += pins; Integer n = 20; } Integer pins = 0; for (Integer i=0; i<n; i++ ) { public Integer score() { g.roll(pins); return score; } } System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } } static testMethod void testAllOnes() { for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 27. Let’s Do Some Clean-up @isTest public with sharing class Game { • Roll loop is duplicated private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { private static void rollMany(Integer n, Integer pins) { score += pins; for (Integer i=0; i<n; i++) { } g.roll(pins); } public Integer score() { } return score; } static testMethod void testGutterGame() { } Integer n = 20; Integer pins = 0; rollMany(n, pins); System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 28. Let’s Do Some Clean-up @isTest public with sharing class Game { • Roll loop is duplicated private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { private static void rollMany(Integer n, Integer pins) { score += pins; for (Integer i=0; i<n; i++) { } g.roll(pins); } public Integer score() { } return score; } static testMethod void testGutterGame() { } rollMany(20, 0); System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { for (Integer i=0; i<20; i++ ) { g.roll(1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 29. Let’s Do Some Clean-up @isTest public with sharing class Game { • Roll loop is duplicated private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { private static void rollMany(Integer n, Integer pins) { score += pins; for (Integer i=0; i<n; i++) { } g.roll(pins); } public Integer score() { } return score; } static testMethod void testGutterGame() { } rollMany(20, 0); System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { rollMany(20, 1); System.assertEquals(20,g.score(), 'An all ones game score not 20'); } }
  • 30. Unit Test #2 - Score should be 20 if bowler knocks down 1 pin every roll Game Integer score public roll(Integer) public score() Next Use Case: Score calculates properly if bowler rolls a spare
  • 31. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { private static void rollMany(Integer n, Integer pins) { score += pins; for (Integer i=0; i<n; i++) { } g.roll(pins); } public Integer score() { } return score; } static testMethod void testGutterGame() { } rollMany(20, 0); System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { rollMany(20, 1); System.assertEquals(20,g.score(), 'An all ones game score not 20'); } static testMethod void testOneSpare() { g.roll(5); g.roll(5); //spare g.roll(3); Ugly comment rollMany(17,0); System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 32. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { private static void rollMany(Integer n, Integer pins) { score += pins; for (Integer i=0; i<n; i++) { } g.roll(pins); } public Integer score() { } return score; } static testMethod void testGutterGame() { } rollMany(20, 0); System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { rollMany(20, 1); System.assertEquals(20,g.score(), 'An all ones game score not 20'); } static testMethod void testOneSpare() { g.roll(5); g.roll(5); //spare g.roll(3); rollMany(17,0); Expected 16 but returned 13 System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 33. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); Tempted to use flag to public void roll(Integer pins) { Remember previous roll. private static void rollMany(Integer n, Integer pins) { score += pins; Design must be wrong. for (Integer i=0; i<n; i++) { } g.roll(pins); } public Integer score() { Roll() calculates score } return score; } static testMethod void testGutterGame() { } score() does not calculate rollMany(20, 0); score, but name implies that it System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } does. static testMethod void testAllOnes() { rollMany(20, 1); System.assertEquals(20,g.score(), 'An all ones game score not 20'); } Design is not going in the right direction. -Methods doing the wrong job static testMethod void testOneSpare() { g.roll(5); -Going down a design path we would rather avoid g.roll(5); //spare g.roll(3); Let’s comment out testOneSpare and do some rollMany(17,0); System.assertEquals(16,g.score(), ‘Spare not scored correctly’); rework } }
  • 34. The Third Test @isTest public with sharing class Game { • Ugly comment in test private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); public void roll(Integer pins) { private static void rollMany(Integer n, Integer pins) { score += pins; for (Integer i=0; i<n; i++) { } g.roll(pins); } public Integer score() { } return score; } static testMethod void testGutterGame() { } rollMany(20, 0); System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } static testMethod void testAllOnes() { rollMany(20, 1); System.assertEquals(20,g.score(), 'An all ones game score not 20'); } // static testMethod void testOneSpare() { // g.roll(5); // g.roll(5); //spare // g.roll(3); // rollMany(17,0); // System.assertEquals(16,g.score(), ‘Spare not scored correctly’); //} }
  • 35. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); private list<Integer> rolls = new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private static void rollMany(Integer n, Integer pins) { private Integer currentRoll = 0; for (Integer i=0; i<n; i++) { g.roll(pins); public void roll(Integer pins) { } score += pins; } rolls[curentRoll++] = pins; } static testMethod void testGutterGame() { rollMany(20, 0); public Integer score() { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); return score; } } } static testMethod void testAllOnes() { rollMany(20, 1); System.assertEquals(20,g.score(), 'An all ones game score not 20'); } // static testMethod void testOneSpare() { // g.roll(5); // g.roll(5); //spare // g.roll(3); // rollMany(17,0); // System.assertEquals(16,g.score(), ‘Spare not scored correctly’); //} }
  • 36. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private Integer score = 0; private static Game g = new Game(); private list<Integer> rolls = new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private static void rollMany(Integer n, Integer pins) { private Integer currentRoll = 0; for (Integer i=0; i<n; i++) { g.roll(pins); public void roll(Integer pins) { } score += pins; } rolls[curentRoll++] = pins; } static testMethod void testGutterGame() { rollMany(20, 0); public Integer score() { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); Integer score = 0; } for (Integer i=0, i<rolls.length; i++) { score += rolls[i]; static testMethod void testAllOnes() { } rollMany(20, 1); return score; System.assertEquals(20,g.score(), 'An all ones game score not 20'); } } } // static testMethod void testOneSpare() { // g.roll(5); // g.roll(5); //spare // g.roll(3); // rollMany(17,0); // System.assertEquals(16,g.score(), ‘Spare not scored correctly’); //} }
  • 37. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); for (Integer i=0, i<rolls.length; i++) { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); score += rolls[i]; } } return score; static testMethod void testAllOnes() { } rollMany(20, 1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } // static testMethod void testOneSpare() { // g.roll(5); // g.roll(5); //spare // g.roll(3); // rollMany(17,0); // System.assertEquals(16,g.score(), ‘Spare not scored correctly’); //} }
  • 38. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); for (Integer i=0, i<rolls.length; i++) { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); score += rolls[i]; } } return score; static testMethod void testAllOnes() { } rollMany(20, 1); } System.assertEquals(20,g.score(), 'An all ones game score not 20'); } static testMethod void testOneSpare() { g.roll(5); g.roll(5); //spare g.roll(3); rollMany(17,0); Expected 16 but returned 13 System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 39. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); for (Integer i=0, i<rolls.length; i++) { System.assertEquals(0,g.score(), ‘Gutter game score not zero'); if (rolls[i] + rolls[i+1] == 10) { //spare } score+=….. } static testMethod void testAllOnes() { score += rolls[i]; rollMany(20, 1); } This isn’t going to work because I System.assertEquals(20,g.score(), 'An all ones game score not 20'); return score; might not refer to the first ball of the } } } frame. static testMethod void testOneSpare() { g.roll(5); Design is still wrong. g.roll(5); //spare g.roll(3); Need to walk through array one rollMany(17,0); frame (two balls) at a time. System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 40. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); Integer i = 0; System.assertEquals(0,g.score(), ‘Gutter game score not zero'); for (Integer frame=0, frame<10; frame++) { } score += rolls[i] + rolls[i+1]; i+=2; static testMethod void testAllOnes() { } rollMany(20, 1); return score; System.assertEquals(20,g.score(), 'An all ones game score not 20'); } } } // static testMethod void testOneSpare() { // g.roll(5); // g.roll(5); //spare // g.roll(3); // rollMany(17,0); // System.assertEquals(16,g.score(), ‘Spare not scored correctly’); //} }
  • 41. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); Integer i = 0; System.assertEquals(0,g.score(), ‘Gutter game score not zero'); for (Integer frame=0, frame<10; frame++) { } score += rolls[i] + rolls[i+1]; i+=2; static testMethod void testAllOnes() { } rollMany(20, 1); return score; System.assertEquals(20,g.score(), 'An all ones game score not 20'); } } } static testMethod void testOneSpare() { g.roll(5); g.roll(5); //spare g.roll(3); Expected 16 but returned 13 rollMany(17,0); System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 42. • Ugly comment in test The Third Test @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); Integer i = 0; System.assertEquals(0,g.score(), ‘Gutter game score not zero'); for (Integer frame=0, frame<10; frame++) { } if (rolls[i] + rolls[i+1] == 10) { //spare score += 10 + rolls[i+2]; static testMethod void testAllOnes() { i += 2; rollMany(20, 1); } else { System.assertEquals(20,g.score(), 'An all ones game score not 20'); score += rolls[i] + rolls[i+1]; } i+=2; } static testMethod void testOneSpare() { } g.roll(5); return score; g.roll(5); //spare } g.roll(3); } rollMany(17,0); System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 43. • Ugly comment in test Some More Clean-up @isTest public with sharing class Game { • Ugly comment in conditional private class BowlingGameTest { private list<Integer> rolls = • i is a bad variable name private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; Bad variable name rollMany(20, 0); Integer i = 0; System.assertEquals(0,g.score(), ‘Gutter game score not zero'); for (Integer frame=0, frame<10; frame++) { } if (rolls[i] + rolls[i+1] == 10) { //spare score += 10 + rolls[i+2]; static testMethod void testAllOnes() { i += 2; rollMany(20, 1); } else { Ugly Comment System.assertEquals(20,g.score(), 'An all ones game score not 20'); score += rolls[i] + rolls[i+1]; } i+=2; } static testMethod void testOneSpare() { } g.roll(5); return score; g.roll(5); //spare } g.roll(3); } rollMany(17,0); System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 44. • Ugly comment in test Some More Clean-up @isTest public with sharing class Game { • Ugly comment in conditional private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); Integer rollsIndex = 0; System.assertEquals(0,g.score(), ‘Gutter game score not zero'); for (Integer frame=0, frame<10; frame++) { } if ( rolls[rollsIndex] + rolls[rollsIndex+1]) { //spare score += 10 + rolls[i+2]; static testMethod void testAllOnes() { rollsIndex += 2; rollMany(20, 1); } else { System.assertEquals(20,g.score(), 'An all ones game score not 20'); score += rolls[rollsIndex] + rolls[rollsIndex+1]; } rollsIndex+=2; } static testMethod void testOneSpare() { } g.roll(5); return score; g.roll(5); //spare } g.roll(3); } rollMany(17,0); System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } }
  • 45. • Ugly comment in test Some More Clean-up @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; private Integer currentRoll = 0; private static void rollMany(Integer n, Integer pins) { for (Integer i=0; i<n; i++) { public void roll(Integer pins) { g.roll(pins); rolls[curentRoll++] = pins; } } } public Integer score() { static testMethod void testGutterGame() { Integer score = 0; rollMany(20, 0); Integer rollsIndex = 0; System.assertEquals(0,g.score(), ‘Gutter game score not zero'); for (Integer frame=0, frame<10; frame++) { } if ( isSpare(rollsIndex)) { score += 10 + rolls[i+2]; static testMethod void testAllOnes() { rollsIndex += 2; rollMany(20, 1); } else { System.assertEquals(20,g.score(), 'An all ones game score not 20'); score += rolls[rollsIndex] + rolls[rollsIndex+1]; } rollsIndex+=2; } static testMethod void testOneSpare() { } g.roll(5); return score; g.roll(5); //spare } g.roll(3); rollMany(17,0); private Boolean isSpare(Integer rollsIndex) { System.assertEquals(16,g.score(), ‘Spare not scored correctly’); return rolls[rollsIndex] + rolls[rollsIndex+1] == 10; } } } }
  • 46. Some More Clean-up @isTest public with sharing class Game { private class BowlingGameTest { private list<Integer> rolls = private static Game g = new Game(); new list<Integer>{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; …….. private Integer currentRoll = 0; static testMethod void testGutterGame() { public void roll(Integer pins) { rollMany(20, 0); rolls[curentRoll++] = pins; System.assertEquals(0,g.score(), ‘Gutter game score not zero'); } } public Integer score() { static testMethod void testAllOnes() { Integer score = 0; rollMany(20, 1); Integer rollsIndex = 0; System.assertEquals(20,g.score(), 'An all ones game score not 20'); for (Integer frame=0, frame<10; frame++) { } if ( isSpare(rollsIndex)) { score += 10 + rolls[i+2]; static testMethod void testOneSpare() { rollsIndex += 2; rollSpare(); } else { g.roll(3); score += rolls[rollsIndex] + rolls[rollsIndex+1]; rollMany(17,0); rollsIndex+=2; System.assertEquals(16,g.score(), ‘Spare not scored correctly’); } } } return score; private static void rollSpare() { } g.roll(5); g.roll(5); private Boolean isSpare(Integer rollsIndex) { } return rolls[rollsIndex] + rolls[rollsIndex+1] == 10; } } }
  • 47. Unit Test #3 – Score calculates properly if bowler rolls a spare Game List rolls Integer currentRoll public roll(Integer) public score() isSpare(Integer) Next Use Case: Score calculates properly if bowler rolls a strike
  • 48. What Have We Seen? A disciplined test-driven approach means… …Clean, more readable code …Refining our design as we go …Quicker feedback …Regression testing becomes trivial
  • 49. Follow-up You finish the app with the following:  https://github.com/knthornt/Dreamforce-2012---TDD-Session  Complete Slide Deck (with tests 4 & 5)  Tests 1 – 3 package  Fully baked version Completed kata video  http://bit.ly/U9dKa8
  • 50. Thank You! Kyle Thornton, Mavens Consulting @knthornt Sean Harrison, Mavens Consulting @GizmoForce Mavens Mav e ns C on su lt in g . c om info@m av en s . i o 312. 7 25. 8 52 8