Bdd: Tdd and beyond the infinite
-
Upload
giordano-scalzo -
Category
Technology
-
view
10.323 -
download
5
Transcript of Bdd: Tdd and beyond the infinite
BEHAVIOUR DRIVEN DEVELOPMENT:TDD AND BEYOND THE INFINITE
Duct Tape Religion War
At the beginning…
end;
// CellText := str;
except
// Gabriele non t'ha beccato, Gigi neppure, a chi toccherà?
end;
end;
while ((!found) && (pos < (fileContent.Length - 6))){ byteData = new byte[6]; Array.Copy(fileContent, pos, byteData, 0, 6); pos = pos + 6; str_byteData = enc.GetString(byteData); if (str_byteData.Contains("s")) { posE_byteData = str_byteData.IndexOf("s"); pos = pos + (posE_byteData - 6); Array.Copy(fileContent, pos, byteData, 0, 6); pos = pos + 6; if (byteData[0] == 0x73) // 's' { if (byteData[1] == 0x74) // 't' { if (byteData[2] == 0x72) // 'r' { if (byteData[3] == 0x65) // 'e' { if (byteData[4] == 0x61) // 'a' { if (byteData[5] == 0x6D) // 'm' { found = true; break; } else { if (byteData[5] == 0x73) { pos = pos - 1; } } }
function TfrmPreviewTrascr.DBToLinear(DB: Double): Double;
begin
//Result := Power(10, DB/20)*1;
Result := Power(10, DB / 100) * 1; { TODO : trovare la relazione corretta }
//LisyLabel4.Caption := Format('%.2f:%.2f', [DB, Result] );
end;
Kent Beck gave Tdd to programmers!
The Three Laws of TDD
The Three Laws of TDD
1 - You are not allowed to write any production code unless it is to make a failing unit test pass.
The Three Laws of TDD
1 - You are not allowed to write any production code unless it is to make a failing unit test pass.
2 - You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
The Three Laws of TDD
1 - You are not allowed to write any production code unless it is to make a failing unit test pass.
2 - You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
3 - You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
TDD Cycle
Is that the end of our problems?
I’m a programmer, not a tester!
My code it’s difficult to test!
It’s a trivial, doesn’t need a test!
I’ve no time to make automatic tests!
It’s about specifications
Sapir-Whorf hypotesis
“there is a systematic relationship between the grammatical categories of the language aperson speaks and how that person both understands the world and behaves in it.”
The Challenge
for(var i = 1; i <= 100; i++){ var output = i + ": "; if(i % 3 == 0) output += "fizz"; if(i % 5 == 0) output += "buzz"; console.log(output);}
48 sec
for(var i = 1; i <= 100; i++){ var output = i + ": "; if(i % 3 == 0) output += "fizz"; if(i % 5 == 0) output += "buzz"; console.log(output);}
But it’s wrong!
puts (1..100).map { |n| '1'*n+":#{n}\n" }.join. gsub(/^(1{5})*:/,'\0Buzz').gsub(/^(1{3})*:/,'Fizz').gsub(/.*:|(z)\d+/,'\1')
WTF?!?!!
package biz.scalzo.tdd;import junit.framework.Assert;import org.junit.Test;import biz.scalzo.tdd.Fizzbuzzer;
public class FizzbuzzTest { @Test public void testForOne(){ Assert.assertEquals("1", new Fizzbuzzer().count(1)); }}
FizzbuzzTest.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int i) { return null; }
}
Fizzbuzzer.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int i) { return "1"; }
}
Fizzbuzzer.java
@Testpublic void testForTwo(){ Assert.assertEquals("2", new Fizzbuzzer().count(2));}
FizzbuzzTest.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int i) { return Integer.toString(i); }
}
Fizzbuzzer.java
@Test public void testForThree(){ Assert.assertEquals("Fizz", new Fizzbuzzer().count(3)); }
FizzbuzzTest.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int i) { if (i == 3) return "Fizz";
return Integer.toString(i); }
}
Fizzbuzzer.java
@Test public void testForFour(){ Assert.assertEquals("4", new Fizzbuzzer().count(4)); }
FizzbuzzTest.java
@Test public void testForFive(){ Assert.assertEquals("Buzz", new Fizzbuzzer().count(5)); }
FizzbuzzTest.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int i) { if (i == 3) return "Fizz"; if (i == 5) return "Buzz";
return Integer.toString(i); }
}
Fizzbuzzer.java
@Test public void testForSix(){ Assert.assertEquals("Fizz", new Fizzbuzzer().count(6)); }
FizzbuzzTest.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int i) { if (i % 3 == 0) return "Fizz"; if (i == 5) return "Buzz";
return Integer.toString(i); }
}
Fizzbuzzer.java
@Test public void testForSeven(){ Assert.assertEquals(“7", new Fizzbuzzer().count(7)); }
FizzbuzzTest.java
@Test public void testForEight(){ Assert.assertEquals(“8", new Fizzbuzzer().count(8)); }
FizzbuzzTest.java
@Test public void testForNine(){ Assert.assertEquals(“Fizz", new Fizzbuzzer().count(9)); }
FizzbuzzTest.java
@Test public void testForTen(){ Assert.assertEquals("Buzz", new Fizzbuzzer().count(10)); }
FizzbuzzTest.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int i) { if (i % 3 == 0) return "Fizz"; if (i % 5 == 0) return "Buzz";
return Integer.toString(i); }
}
Fizzbuzzer.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int number) { if (isMultipleOf(number, 3)) return "Fizz"; if (isMultipleOf(number, 5)) return "Buzz";
return Integer.toString(number); }
private boolean isMultipleOf(int number, int multiple) { return number % multiple == 0; }}
Fizzbuzzer.java
@Test public void testForFifteen(){ Assert.assertEquals("FizzBuzz", new Fizzbuzzer().count(15)); }
FizzbuzzTest.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int number) { if (isMultipleOf(number, 3) && isMultipleOf(number, 5)) return "FizzBuzz"; if (isMultipleOf(number, 3)) return "Fizz"; if (isMultipleOf(number, 5)) return "Buzz";
return Integer.toString(number); }
private boolean isMultipleOf(int number, int multiple) { return number % multiple == 0; }}
Fizzbuzzer.java
package biz.scalzo.tdd;
public class Fizzbuzzer {
public String count(int number) { String fizzOrBuzz = fizz(number) + buzz(number); return fizzOrBuzz.equals("") ? Integer.toString(number) : fizzOrBuzz; }
private boolean isMultipleOf(int number, int multiple) { return number % multiple == 0; }
private String fizz(int number) { return isMultipleOf(number, 3) ? "Fizz" : ""; }
private String buzz(int number) { return isMultipleOf(number, 5) ? "Buzz" : ""; }}
Fizzbuzzer.java
Result
package biz.scalzo.tdd;import junit.framework.Assert;import org.junit.Test;import biz.scalzo.tdd.Fizzbuzzer;
public class FizzbuzzTest { @Test public void testForOne(){ Assert.assertEquals("1", new Fizzbuzzer().count(1)); }
@Test public void testForTwo(){ Assert.assertEquals("2", new Fizzbuzzer().count(2)); }
@Test public void testForThree(){ Assert.assertEquals("Fizz", new Fizzbuzzer().count(3)); }
@Test public void testForFive(){ Assert.assertEquals("Buzz", new Fizzbuzzer().count(5)); }
@Test public void testForSix(){ Assert.assertEquals("Fizz", new Fizzbuzzer().count(6)); }
FizzbuzzTest.java
@Test public void testForSeven(){ Assert.assertEquals("7", new Fizzbuzzer().count(7)); }
@Test public void testForEight(){ Assert.assertEquals("8", new Fizzbuzzer().count(8)); }
@Test public void testForNine(){ Assert.assertEquals("Fizz", new Fizzbuzzer().count(9)); }
@Test public void testForTen(){ Assert.assertEquals("Buzz", new Fizzbuzzer().count(10)); }
@Test public void testForFifteen(){ Assert.assertEquals("FizzBuzz", new Fizzbuzzer().count(15)); }}
FizzbuzzTest.java
Bdd Way
Bdd Way
Test method names should be sentences
package biz.scalzo.bdd;
import java.util.ArrayList;import java.util.List;
import org.junit.Test;import static org.hamcrest.MatcherAssert.assertThat;import static org.hamcrest.Matchers.*;
public class AFizzbuzzer { @Test public void shouldYellOneForOne() { assertThat(new Fizzbuzzer().count(1), is(equalTo("1"))); }}
AFizzbuzzer.java
package biz.scalzo.bdd;
import java.util.ArrayList;import java.util.List;
import org.junit.Test;import static org.hamcrest.MatcherAssert.assertThat;import static org.hamcrest.Matchers.*;
public class AFizzbuzzer { @Test public void shouldYellOneForOne() { assertThat(new Fizzbuzzer().count(1), is(equalTo("1"))); }}
AFizzbuzzer.java
Bdd Way
the class should do something
package biz.scalzo.bdd;
import java.util.ArrayList;import java.util.List;
import org.junit.Test;import static org.hamcrest.MatcherAssert.assertThat;import static org.hamcrest.Matchers.*;
public class AFizzbuzzer { @Test public void shouldYellOneForOne() { assertThat(new Fizzbuzzer().count(1), is(equalTo("1"))); }}
AFizzbuzzer.java
package biz.scalzo.bdd;
import java.util.ArrayList;import java.util.List;
import org.junit.Test;import static org.hamcrest.MatcherAssert.assertThat;import static org.hamcrest.Matchers.*;
public class AFizzbuzzer { @Test public void shouldYellOneForOne() { assertThat(new Fizzbuzzer().count(1), is(equalTo("1"))); }}
AFizzbuzzer.java
@Test public void shouldYellTwoForTwo() { assertThat(new Fizzbuzzer().count(2), is(equalTo("2"))); }
AFizzbuzzer.java
@Test public void shouldYellFizzForMultipleOfThree() { int[] fizzers = { 3, 6, 9, 12, 18 }; for (int fizzer : fizzers) { assertThat(new Fizzbuzzer().count(fizzer), is(equalTo("Fizz"))); } }
AFizzbuzzer.java
@Test public void shouldYellBuzzForMultipleOfFive() { int[] buzzers = { 5, 10 }; for (int buzzer : buzzers) { assertThat(new Fizzbuzzer().count(buzzer), is(equalTo("Buzz"))); } }
AFizzbuzzer.java
@Test public void shouldYellFizzBuzzForMultipleOfThreeAndFive() { int[] fizzBuzzers = { 15, 30, 45, 60 }; for (int fizzBuzzer : fizzBuzzers ) { assertThat(new Fizzbuzzer().count(fizzBuzzer), is(equalTo("FizzBuzz"))); } }
AFizzbuzzer.java
@Test public void shouldYellTheNumberForNotMultipleOfThreeOrFive() { for (int plainNumber : plainNumbers()) { assertThat(new Fizzbuzzer().count(plainNumber), is(equalTo(Integer .toString(plainNumber)))); } }
private List<Integer> plainNumbers() { List<Integer> numbers = new ArrayList<Integer>(); for (int i = 1; i <= 100; i++) numbers.add(i); for (int i = 1; i < 35; i++) numbers.remove(new Integer(i * 3));
for (int i = 1; i < 25; i++) numbers.remove(new Integer(i * 5)); return numbers; }
AFizzbuzzer.java
Fathers of Bdd
The Ruby Way to Bdd
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
require "fizzbuzzer"
describe "Fizzbuzzer" do it "should yell one for one" do Fizzbuzzer.new.count(1).should == '1' endend
fizzbuzzer_spec.rb
it "should yell two for two" do Fizzbuzzer.new.count(2).should == '2' end
fizzbuzzer_spec.rb
it "should yell Fizz for three" do Fizzbuzzer.new.count(3).should == 'Fizz' end
fizzbuzzer_spec.rb
it "should yell Fizz for multiple of three" do [3, 6, 9, 12].each do |number| Fizzbuzzer.new.count(number).should == 'Fizz' end end
fizzbuzzer_spec.rb
it "should yell Buzz for multiple of five" do [5, 10].each do |number| Fizzbuzzer.new.count(number).should == 'Buzz' end end
fizzbuzzer_spec.rb
it "should yell FizzBuzz for multiple of three and five" do [15, 30, 45].each do |number| Fizzbuzzer.new.count(number).should == 'FizzBuzz' end end
fizzbuzzer_spec.rb
it "should yell the number itself for non multiple of three or five" do (1..100).select { |n| n % 3 != 0 && n % 5 != 0}.each do |number| Fizzbuzzer.new.count(number).should == number.to_s end end
fizzbuzzer_spec.rb
Result
class Fixnum def fizzbuzzed? "FizzBuzz" if self % 3 == 0 && self % 5 == 0 end def fizzed? "Fizz" if self % 3 == 0 end def buzzed? "Buzz" if self % 5 == 0 endend
class Fizzbuzzer def count(number) number.fizzbuzzed? || number.fizzed? || number.buzzed? || number.to_s endend
fizzbuzzer.rb
describe "Fizzbuzzer" do it "should yell one for one" do Fizzbuzzer.new.count(1).should == '1' end it "should yell two for two" do Fizzbuzzer.new.count(2).should == '2' end it "should yell Fizz for multiple of three" do [3, 6, 9, 12].each do |number| Fizzbuzzer.new.count(number).should == 'Fizz' end end it "should yell Buzz for multiple of five" do [5, 10].each do |number| Fizzbuzzer.new.count(number).should == 'Buzz' end end it "should yell FizzBuzz for multiple of three and five" do [15, 30, 45].each do |number| Fizzbuzzer.new.count(number).should == 'FizzBuzz' end end it "should yell the number itself for non multiple of three or five" do (1..100).select { |n| n % 3 != 0 && n % 5 != 0}.each do |number| Fizzbuzzer.new.count(number).should == number.to_s end endend
fizzbuzzer_spec.rb
output
output
Stories
As a [role]I want [feature]So that [benefit]
Story
Scenario 1: TitleGiven [context] And [some more context]...When [event]Then [outcome] And [another outcome]
Scenario Acceptance Criteria
Cucumber
Cucumber
fizzbuzzer.featurefizzbuzzer_steps.rb
Feature: perfect fizzbuzzing As a inattentive counter I want an automatic Fizzbuzzer So that I can win Fizzbuzz Championsip
fizzbuzzer.feature
Scenario: manage fizz numbers Given a Fizzbuzzer When I ask for a multiple of 3 Then Fizzbuzzer yells 'Fizz'
fizzbuzzer.feature
require "fizzbuzzer"
Given "a Fizzbuzzer" do @fizzbuzzer = Fizzbuzzer.newend
When "I ask for a multiple of $m" do |m| @result = [1, 2].map { |base| @fizzbuzzer.count(base*eval(m).to_i) }end
Then "Fizzbuzzer yells '$yell'" do |yell| @result.each do |result| result.should == yell endend
fizzbuzzer_steps.rb
Scenario: manage buzz numbers Given a Fizzbuzzer When I ask for a multiple of 5 Then Fizzbuzzer yells 'Buzz'
Scenario: manage fizzbuzz numbers Given a Fizzbuzzer When I ask for a multiple of 3*5 Then Fizzbuzzer yells 'FizzBuzz'
fizzbuzzer.feature
Scenario: manage plain numbers Given a Fizzbuzzer When I ask for a plain number Then Fizzbuzzer yells the number itself
fizzbuzzer.feature
When "I ask for a plain number" do @expected = (1..100).select { |n| n % 3 != 0 && n % 5 != 0}
@result = @expected.each do |number| @fizzbuzzer.count(number).to_i end
end
Then "Fizzbuzzer yells the number itself" do @result.should == @expectedend
fizzbuzzer_steps.rb
Scenario Outline: manage plain numbers Given a Fizzbuzzer When I ask for '<number>' Then Fizzbuzzer yells '<result>' Examples: | number | result | | 1 | 1 | | 2 | 2 | | 3 | Fizz | | 4 | 4 | | 5 | Buzz | | 6 | Fizz |
fizzbuzzer.feature
When "I ask for '$m'" do |number| @result = @fizzbuzzer.count(number.to_i)end
Then "Fizzbuzzer yells '$yell'" do |yell| @result.each do |result| result.should == yell endend
fizzbuzzer_steps.rb
neat, isn’t it?
Back to Java
Where it all started
jbehave
manage_fizzbuzzerManageFizzbuzzer.javaManageFizzbuzzerSteps.java
Feature: perfect fizzbuzzing As a inattentive counter I want an automatic Fizzbuzzer So that I can win Fizzbuzz Championsip
Scenario: manage fizz numbers Given a Fizzbuzzer When I ask for a multiple of 3 Then Fizzbuzzer yells 'Fizz'
Scenario: manage buzz numbers Given a Fizzbuzzer When I ask for a multiple of 5 Then Fizzbuzzer yells 'Buzz'
Scenario: manage fizzbuzz numbers Given a Fizzbuzzer When I ask for a multiple of 15 Then Fizzbuzzer yells 'FizzBuzz'
manage_fizzbuzzer
Scenario: manage plain numbers Given a Fizzbuzzer When I ask for a plain number Then Fizzbuzzer yells the number itself
Scenario: manage plain numbers Given a Fizzbuzzer When I ask for '[number]' Then Fizzbuzzer yells '[yell]'
Examples: | number | yell | | 1 | 1 | | 2 | 2 | | 3 | Fizz | | 4 | 4 | | 5 | Buzz | | 6 | Fizz |
manage_fizzbuzzer
package biz.scalzo.jbehave;
import org.jbehave.scenario.Scenario;
public class ManageFizzbuzzer extends Scenario { public ManageFizzbuzzer() { super(new ManageFizzbuzzerSteps()); }}
ManageFizzbuzzer.java
import biz.scalzo.bdd.Fizzbuzzer;
public class ManageFizzbuzzerSteps extends Steps { private Fizzbuzzer fizzbuzzer; private List<String> results; private List<String> expected; private String result;
@BeforeScenario public void setUp() { expected = new ArrayList<String>(); results = new ArrayList<String>(); }
ManageFizzbuzzerSteps.java
@Given("a Fizzbuzzer") public void startFizzbuzzer() { fizzbuzzer = new Fizzbuzzer(); }
@When("I ask for a multiple of $divisor") public void askForMultipleOf(int divisor) { for (int number = 1; number < 3; ++number) results.add(fizzbuzzer.count(number * divisor)); }
@Then("Fizzbuzzer yells '$yell'") public void checkYell(String yell) { for (String result : results) { assertThat(result, is(equalTo(yell))); } }
ManageFizzbuzzerSteps.java
@When("I ask for a plain number") public void askForPlainNumbers() { for (int i = 1; i <= 100; i++) if (i % 3 != 0 && i % 5 != 0) expected.add(Integer.toString(i));
for (String number : expected) results.add(fizzbuzzer.count(Integer.parseInt(number))); }
@Then("Fizzbuzzer yells the number itself") public void yellsNumberItself() { for (int i = 0; i < expected.size(); i++) { assertThat(results.get(i), is(equalTo(expected.get(i)))); } }
ManageFizzbuzzerSteps.java
@When("I ask for '[number]'") public void askFor(@Named("number") int number) { result = fizzbuzzer.count(number); }
@Then("Fizzbuzzer yells '[yell]'") public void checkResult(@Named("yell") String yell) { assertThat(result, is(equalTo(yell))); }
ManageFizzbuzzerSteps.java
Other Frameworks
•ASSpec ActionScript 3•CppSpec C++•Spec- cpp C++•CSpec C•cfSpec ColdFusion•dSpec Delphi•easyb Groovy•EasySpec Groovy•tspec Groovy•GSpec Groovy•Concordion Java•GivWenZen Java•Instinct Java•JavaStubs Java•JBehave Java•JDave Java•beanSpec Java•JFXtras Test JavaFX•JSpec JavaScript•JSSpec JavaScript•Screw- unit JavaScript
Other Frameworks
•NBehave .Net•NSpec .Net•NSpecify .Net•SpecUnit .Net•NUnit .Net•Specter .Net•StoryQ .Net•ObjectiveMatchy iPhone•PHPSpec PHP•Pyccuracy Python•Pyhistorian Python•PyCukes Python•Robot Framework Python•ScalaTest Scala•specs Scala
Other Frameworks
Conclusions?
Bdd is about specifications
Homework
http://github.com/coreyhaines/practice_game_of_life
Feature: Evolving a living cell In order to create a functioning rules engine As a programmer of Conway's Game of Life I can evolve a single living cell Scenario: Living cell with 0 neighbors dies Given the following setup | . | . | . | | . | x | . | | . | . | . | When I evolve the board Then the center cell should be dead Scenario: Living cell with 1 neighbor dies Given the following setup | . | x | . | | . | x | . | | . | . | . | When I evolve the board Then the center cell should be dead Scenario: Living cell with 2 neighbors lives Given the following setup | . | x | . | | . | x | x | | . | . | . | When I evolve the board Then the center cell should be alive Scenario: Living cell with 3 neighbors lives Given the following setup | x | x | x | | . | x | . | | . | . | . | When I evolve the board Then the center cell should be alive
Start Bdd now!
? ? ????