143
TESTING THE NEXT GENERATION MIKE HARRIS

Testing the Next Generation

Embed Size (px)

DESCRIPTION

Testing: the final frontier. These are the voyages of Software Craftsmanship. Its continuing mission: to explore strange new worlds, to seek out new code and new patterns, to boldly go where no one has gone before. Looking to take your testing to new worlds? Want to verify your code meetings your user's requirements? Come learn about behavior and property testing in .Net. We'll look at how SpecFlow can get everyone on the same page and how to find more edge cases with property testing using FsCheck.

Citation preview

Page 1: Testing the Next Generation

T E S T I N G T H E N E X T G E N E R AT I O N

M I K E H A R R I S

Page 2: Testing the Next Generation
Page 3: Testing the Next Generation

fscheck

specflow

Page 4: Testing the Next Generation

is testing oftraits

specflow

Page 5: Testing the Next Generation

is testing ofproperties

fscheck

Page 6: Testing the Next Generation
Page 7: Testing the Next Generation

B E I N G

Page 8: Testing the Next Generation
Page 9: Testing the Next Generation
Page 10: Testing the Next Generation
Page 11: Testing the Next Generation
Page 12: Testing the Next Generation

B E I N G

Page 13: Testing the Next Generation

B E I N G T H I N G S

Page 14: Testing the Next Generation

B E I N G T H I N G S

A S M A R T I N H E I D E G G E R S P E A K S O F T H E M I N

“ T H E O R I G I N O F T H E W O R K O F A R T "

Page 15: Testing the Next Generation

I N T E R P R E TAT I O N S O F T H I N G S

• substances with properties or as bearers of traits

• sense perceptions

• formed stuff

Page 16: Testing the Next Generation

S U B S TA N C E S W I T H P R O P E R T I E S O R A S B E A R E R S O F T R A I T S

Page 17: Testing the Next Generation
Page 18: Testing the Next Generation

fscheck

specflow

Page 19: Testing the Next Generation

is testing oftraits

specflow

Page 20: Testing the Next Generation

is testing ofproperties

fscheck

Page 21: Testing the Next Generation

S U B S TA N C E S W I T H P R O P E R T I E S O R A S B E A R E R S O F T R A I T S

Page 22: Testing the Next Generation
Page 23: Testing the Next Generation

Testing of Traits

Page 24: Testing the Next Generation

is testing oftraits

specflow

Page 25: Testing the Next Generation
Page 26: Testing the Next Generation

I N E E D A F I Z Z B U Z Z T R A N S L AT O R

Page 27: Testing the Next Generation

C H E C K P O I N T 1 ) N O B M I ' D I V I S I B L E P O N G 3 F I Z Z J I C H E G H ' O H . N O B M I ' D I V I S I B L E P O N G 5 B U Z Z J I C H E G H ' O H . L AT L H S O ' M E H J I C H E G H ‘ O H . !2 )⎕ I O← 0 ( L , ' F I Z Z ' ' B U Z Z ' ' F I Z Z B U Z Z ' ) [ ¯ 1 +( L×W = 0 ) + W← ( 1 0 0×~ 0 = W ) + W←⊃ + / 1 2× 0 = 3 5 |

⊂ L← 1 +⍳ 1 0 0 ]

Page 28: Testing the Next Generation

S A M E PA G E !

Page 29: Testing the Next Generation

C H E C K P O I N T 2 - > 2 3 - > F I Z Z 4 - > 4 5 - > B U Z Z 6 - > F I Z Z

Page 30: Testing the Next Generation

M A K E I T S O .

Page 31: Testing the Next Generation
Page 32: Testing the Next Generation

F I Z Z B U Z Z

Page 33: Testing the Next Generation

FizzBuzz(1 ) => “1” FizzBuzz(2 ) => “2” FizzBuzz(3 ) => “Fizz” FizzBuzz(4 ) => “4” FizzBuzz(5 ) => “Buzz” FizzBuzz(6 ) => “Fizz” … FizzBuzz(15) => “FizzBuzz”

Page 34: Testing the Next Generation

namespace FizzBuzz { public class FizzBuzzer { public string Translate(int value) { var result = string.Empty; if (value % 3 == 0) result += "Fizz"; if (value % 5 == 0) result += "Buzz"; return string.IsNullOrEmpty(result) ? value.ToString() : result; } } }

Page 35: Testing the Next Generation

T E S T I N G T R A I T S

Page 36: Testing the Next Generation

T H E N U N I T W AY

Page 37: Testing the Next Generation

[TestCase( 2, Result = "2")] [TestCase( 3, Result = "Fizz")] [TestCase( 4, Result = "4")] [TestCase( 5, Result = "Buzz")] [TestCase( 6, Result = "Fizz")] [TestCase(10, Result = "Buzz")] [TestCase(15, Result = "FizzBuzz")] [TestCase(45, Result = "FizzBuzz")] public string FizzBuzz_Tests(int value) { return fizzbuzzer.Translate(value); }

Page 38: Testing the Next Generation

S P E C F L O W W AY

Page 39: Testing the Next Generation

Feature: FizzBuzzerSpec In order to be able to communicate with the FizzBuzzons As a Starfleet Captain I want to be able to translate numbers to their FizzBuzz value

Page 40: Testing the Next Generation

Scenario: 2 must translate to the string 2 Given a FizzBuzzer And the value of '2' When translate is invoked Then the result should be '2'

Page 41: Testing the Next Generation

Scenario: 3 must translate to the string Fizz Given a FizzBuzzer And the value of '3' When translate is invoked Then the result should be 'Fizz'

Page 42: Testing the Next Generation

Scenario: 5 must translate to the string Buzz Given a FizzBuzzer And the value of '5' When translate is invoked Then the result should be 'Buzz'

Page 43: Testing the Next Generation

Scenario: 15 must translate to the string FizzBuzz Given a FizzBuzzer And the value of '15' When translate is invoked Then the result should be 'FizzBuzz'

Page 44: Testing the Next Generation

Feature: FizzBuzzerSpec In order to be able to communicate with the FizzBuzzons As a Starfleet Captain I want to be able to translate numbers to their FizzBuzz value Scenario: 2 must translate to the string 2 Given a FizzBuzzer And the value of '2' When translate is invoked Then the result should be '2' Scenario: 3 must translate to the string Fizz Given a FizzBuzzer And the value of '3' When translate is invoked Then the result should be 'Fizz' Scenario: 5 must translate to the string Buzz Given a FizzBuzzer And the value of '5' When translate is invoked Then the result should be 'Buzz' Scenario: 15 must translate to the string FizzBuzz Given a FizzBuzzer And the value of '15' When translate is invoked Then the result should be 'FizzBuzz'

Page 45: Testing the Next Generation
Page 46: Testing the Next Generation

Feature: FizzBuzzerSpec In order to be able to communicate with the FizzBuzzons As a Starfleet Captain I want to be able to translate numbers to their FizzBuzz value

Page 47: Testing the Next Generation

Scenario: 2 must translate to the string 2 Given a FizzBuzzer And the value of '2' When translate is invoked Then the result should be '2'

Page 48: Testing the Next Generation

using FizzBuzz; using TechTalk.SpecFlow; using NUnit.Framework; namespace FizzBuzzSpec { [Binding] public class FizzBuzzerSpecSteps { [Given(@"a FizzBuzzer")] public void GivenAFizzBuzzer() { ScenarioContext.Current.Add("FizzBuzzer", new FizzBuzzer()); } [Given(@"the value of '(.*)'")] public void GivenTheValueOf(int value) { ScenarioContext.Current.Add("value", value); } [When(@"translate is invoked")] public void WhenTranslateIsInvoked() { var fizzbuzzer = ScenarioContext.Current.Get<FizzBuzzer>("FizzBuzzer"); var value = ScenarioContext.Current.Get<int>("value"); ScenarioContext.Current.Add("actual", fizzbuzzer.Translate(value)); } [Then(@"the result should be '(.*)'")] public void ThenTheResultShouldBe(string expected) { var actual = ScenarioContext.Current.Get<string>("actual"); Assert.That(expected, Is.EqualTo(actual)); } } }

Page 49: Testing the Next Generation

Given a FizzBuzzer !

[Given(@"a FizzBuzzer")] public void GivenAFizzBuzzer() { ScenarioContext.Current.Add( "FizzBuzzer", new FizzBuzzer()); }

Page 50: Testing the Next Generation

And the value of '2' !

[Given(@"the value of '(.*)'")] public void GivenTheValueOf(int value) { ScenarioContext.Current.Add("value", value); }

Page 51: Testing the Next Generation

When translate is invoked [When(@"translate is invoked")] public void WhenTranslateIsInvoked() { var fizzbuzzer = ScenarioContext .Current.Get<FizzBuzzer>("FizzBuzzer"); var value = ScenarioContext .Current.Get<int>("value"); ScenarioContext .Current.Add( "actual", fizzbuzzer.Translate(value)); }

Page 52: Testing the Next Generation

Then the result should be '2' [Then(@"the result should be '(.*)'")] public void ThenTheResultShouldBe( string expected) { var actual = ScenarioContext .Current.Get<string>("actual"); Assert.That(expected, Is.EqualTo(actual)); }

Page 53: Testing the Next Generation

Scenario: 2 must translate to the string 2 Given a FizzBuzzer And the value of '2' When translate is invoked Then the result should be '2'

Page 54: Testing the Next Generation

Scenario: 5 must translate to the string Buzz Given a FizzBuzzer And the value of '5' When translate is invoked Then the result should be 'Buzz'

Page 55: Testing the Next Generation

Given a FizzBuzzer !

[Given(@"a FizzBuzzer")] public void GivenAFizzBuzzer() { ScenarioContext.Current.Add( "FizzBuzzer", new FizzBuzzer()); }

Page 56: Testing the Next Generation

And the value of '5' !

[Given(@"the value of '(.*)'")] public void GivenTheValueOf(int value) { ScenarioContext.Current.Add("value", value); }

Page 57: Testing the Next Generation

When translate is invoked [When(@"translate is invoked")] public void WhenTranslateIsInvoked() { var fizzbuzzer = ScenarioContext .Current.Get<FizzBuzzer>("FizzBuzzer"); var value = ScenarioContext .Current.Get<int>("value"); ScenarioContext .Current.Add( "actual", fizzbuzzer.Translate(value)); }

Page 58: Testing the Next Generation

Then the result should be 'Buzz' [Then(@"the result should be '(.*)'")] public void ThenTheResultShouldBe( string expected) { var actual = ScenarioContext .Current.Get<string>("actual"); Assert.That(expected, Is.EqualTo(actual)); }

Page 59: Testing the Next Generation
Page 60: Testing the Next Generation
Page 61: Testing the Next Generation
Page 62: Testing the Next Generation

Scenario: 2 must translate to the string 2 Given a FizzBuzzer And the value of '2' When translate is invoked Then the result should be '2'

Page 63: Testing the Next Generation

[NUnit.Framework.TestAttribute()] [NUnit.Framework.DescriptionAttribute("2 must translate to the string 2")] public virtual void _2MustTranslateToTheString2() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo( "2 must translate to the string 2", ((string[])(null))); #line 6 this.ScenarioSetup(scenarioInfo); #line 7 testRunner.Given("a FizzBuzzer", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Given "); #line 8 testRunner.And("the value of \'2\'", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "And "); #line 9 testRunner.When("translate is invoked", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "When "); #line 10 testRunner.Then("the result should be \'2\'", ((string)(null)), ((TechTalk.SpecFlow.Table)(null)), "Then "); #line hidden this.ScenarioCleanup(); }

Page 64: Testing the Next Generation

G O O D , B U T N O T G R E AT.

Page 65: Testing the Next Generation
Page 66: Testing the Next Generation

Examples: | value | expected value | | 2 | 2 | | 4 | 4 | | 3 | Fizz | | 9 | Fizz | | 5 | Buzz | | 25 | Buzz | | 15 | FizzBuzz | | 30 | FizzBuzz |

Page 67: Testing the Next Generation

Scenario Outline: FizzBuzz translation Given a FizzBuzzer And the value of '<value>' When translate is invoked Then the result should be '<expected value>' Examples: | value | expected value | | 2 | 2 | | 4 | 4 | | 3 | Fizz | | 9 | Fizz | | 5 | Buzz | | 25 | Buzz | | 15 | FizzBuzz | | 30 | FizzBuzz |

Page 68: Testing the Next Generation

[Given(@"a FizzBuzzer")] public void GivenAFizzBuzzer() { ScenarioContext.Current.Add( "FizzBuzzer", new FizzBuzzer()); }

Page 69: Testing the Next Generation

[Given(@"the value of '(.*)'")] public void GivenTheValueOf(int value) { ScenarioContext.Current.Add("value", value); }

Page 70: Testing the Next Generation

[When(@"translate is invoked")] public void WhenTranslateIsInvoked() { var fizzbuzzer = ScenarioContext .Current.Get<FizzBuzzer>("FizzBuzzer"); var value = ScenarioContext .Current.Get<int>("value"); ScenarioContext .Current.Add( "actual", fizzbuzzer.Translate(value)); }

Page 71: Testing the Next Generation

[Then(@"the result should be '(.*)'")] public void ThenTheResultShouldBe( string expected) { var actual = ScenarioContext .Current.Get<string>("actual"); Assert.That(expected, Is.EqualTo(actual)); }

Page 72: Testing the Next Generation

Examples: | value | expected value | | 2 | 2 | | 4 | 4 | | 3 | Fizz | | 9 | Fizz | | 5 | Buzz | | 25 | Buzz | | 15 | FizzBuzz | | 30 | FizzBuzz |

Page 73: Testing the Next Generation

[TestCase( 2, Result = "2")] [TestCase( 3, Result = "Fizz")] [TestCase( 4, Result = "4")] [TestCase( 5, Result = "Buzz")] [TestCase( 6, Result = "Fizz")] [TestCase(10, Result = "Buzz")] [TestCase(15, Result = "FizzBuzz")] [TestCase(45, Result = "FizzBuzz")] public string FizzBuzz_Tests(int value) { return fizzbuzzer.Translate(value); }

Page 74: Testing the Next Generation

Examples: | value | expected value | | 2 | 2 | | 4 | 4 | | 3 | Fizz | | 9 | Fizz | | 5 | Buzz | | 25 | Buzz | | 15 | FizzBuzz | | 30 | FizzBuzz |

Page 75: Testing the Next Generation

G R E AT.

Page 76: Testing the Next Generation
Page 77: Testing the Next Generation
Page 78: Testing the Next Generation
Page 79: Testing the Next Generation
Page 80: Testing the Next Generation
Page 81: Testing the Next Generation
Page 82: Testing the Next Generation

"FizzBuzzSpec\FizzBuzzSpec\FizzBuzzerSpecFeature\_15MustTranslateToTheStringFizzBuzz","Passed","00:00:00.183","(local)" Given a FizzBuzzer -> done: FizzBuzzerSpecSteps.GivenAFizzBuzzer() (0.0s) And the value of '15' -> done: FizzBuzzerSpecSteps.GivenTheValueOf(15) (0.0s) When translate is invoked -> done: FizzBuzzerSpecSteps.WhenTranslateIsInvoked() (0.0s) Then the result should be 'FizzBuzz' -> done: FizzBuzzerSpecSteps.ThenTheResultShouldBe("FizzBuzz") (0.0s)

Page 83: Testing the Next Generation
Page 84: Testing the Next Generation
Page 85: Testing the Next Generation
Page 86: Testing the Next Generation
Page 87: Testing the Next Generation
Page 88: Testing the Next Generation

D O E S T H I S R E A L LY W O R K ? ! ?

Page 89: Testing the Next Generation

W E C O U L D H AV E T H E S Y S T E M G E N E R AT E D ATA F O R U S

T O I L L U S T R AT E T H E A D H E R E N C E O F P R O P E R T I E S

Page 90: Testing the Next Generation

M A K E I T S O .

Page 91: Testing the Next Generation
Page 92: Testing the Next Generation

Testing of Properties

Page 93: Testing the Next Generation

is testing ofproperties

fscheck

Page 94: Testing the Next Generation

T E S T I N G P R O P E R T I E S

Page 95: Testing the Next Generation

T H E N U N I T W AY

Page 96: Testing the Next Generation

[Test] public void Divisible_By_3_Is_Fizz( [Range(3, 300, 3)] int value) { var removeBuzz = (value % 5 == 0) ? 3 : value; Assert.That(FizzBuzz(removeBuzz), Is.EqualTo("Fizz")); }

Page 97: Testing the Next Generation

[Test] public void Divisible_By_5_Is_Buzz( [Random(1, 10000, 100)] int value) { var removeFizz = (value % 3 == 0) ? 5 : value * 5; Assert.That(FizzBuzz(removeFizz), Is.EqualTo("Buzz")); }

Page 98: Testing the Next Generation

F S C H E C K W AY

Page 99: Testing the Next Generation

[TestCase] public void Number_Divisible_By_3_Will_Return_Fizz() { Spec.ForAny<int>(value => _fizzBuzzer.Translate(value).Equals("Fizz")) .When(value => value % 3 == 0 && value % 5 != 0) .QuickCheckThrowOnFailure(); }

Page 100: Testing the Next Generation

Ok, passed 100 tests.

Page 101: Testing the Next Generation

[TestCase] public void Number_Divisible_By_5_Will_Return_Buzz() { Spec.ForAny<int>(value => _fizzBuzzer.Translate(value).Equals("Buzz")) .When(value => value % 3 != 0 && value % 5 == 0) .QuickCheckThrowOnFailure(); }

Page 102: Testing the Next Generation

Ok, passed 100 tests.

Page 103: Testing the Next Generation

[TestCase] public void Number_Divisible_By_15_Returns_FizzBuzz() { Spec.ForAny<int>(value => _fizzBuzzer.Translate(value).Equals("FizzBuzz")) .Or(value => value % 15 != 0) .QuickCheckThrowOnFailure(); }

Page 104: Testing the Next Generation

Ok, passed 100 tests.

Page 105: Testing the Next Generation

H M M M M

Page 106: Testing the Next Generation

W E C O U L D C R E AT E A M O D E L T O D E M O N S T R AT E T H E

R O B U S T N E S S O F T H E S O L U T I O N

Page 107: Testing the Next Generation

M A K E I T S O .

Page 108: Testing the Next Generation

T E S T I N G A G A I N S T A M O D E L

Page 109: Testing the Next Generation

F S C H E C K W AY

Page 110: Testing the Next Generation

class FizzBuzzModel { public static string Translate(int value) { if (value % 15 == 0) return "FizzBuzz"; if (value % 3 == 0) return "Fizz"; if (value % 5 == 0) return "Buzz"; return value.ToString(CultureInfo.InvariantCulture); } } [TestCase] public void Will_Match_Model() { Spec.ForAny<int>(value => FizzBuzzModel.Translate(value).Equals(_fizzBuzzer.Translate(value))) .QuickCheckThrowOnFailure(); }

Page 111: Testing the Next Generation

class FizzBuzzModel { public static string Translate(int value) { if (value % 15 == 0) return "FizzBuzz"; if (value % 3 == 0) return "Fizz"; if (value % 5 == 0) return "Buzz"; return value.ToString(CultureInfo.InvariantCulture); } }

Page 112: Testing the Next Generation

[TestCase] public void Will_Match_Model() { Spec.ForAny<int>(value => FizzBuzzModel.Translate(value) .Equals(_fizzBuzzer.Translate(value))) .QuickCheckThrowOnFailure(); }

Page 113: Testing the Next Generation

Ok, passed 100 tests.

Page 114: Testing the Next Generation

H M M M M

Page 115: Testing the Next Generation

W E C O U L D U S E A S Y S T E M T O G E N E R AT E

D E G E N E R AT I V E T E S T D ATA T O D I S P L AY C O R R E C T N E S S

Page 116: Testing the Next Generation

M A K E I T S O .

Page 117: Testing the Next Generation

T E S T I N G N E G AT I O N

Page 118: Testing the Next Generation

F S C H E C K W AY

Page 119: Testing the Next Generation

[TestCase] public void Numbers_Not_Divisible_By_3_Do_Not_Fizz() { var noThrees = from number in Any.OfType<int>() where number%3 != 0 select number; Spec.For(noThrees, x => _fizzBuzzer.Translate(x) .Contains("Fizz") == false) .QuickCheckThrowOnFailure(); }

Page 120: Testing the Next Generation

Ok, passed 100 tests.

Page 121: Testing the Next Generation

[TestCase] public void Numbers_Not_Divisible_By_5_Do_Not_Buzz() { var noFives = from number in Any.OfType<int>() where number%5 != 0 select number; Spec.For(noFives, x => _fizzBuzzer.Translate(x) .Contains("Buzz") == false) .QuickCheckThrowOnFailure(); }

Page 122: Testing the Next Generation

Ok, passed 100 tests.

Page 123: Testing the Next Generation

H M M M M

Page 124: Testing the Next Generation

[TestCase] public void Numbers_Divisible_By_15_Must_FizzBuzz() { var onlyFifteens = from number in Any.OfType<int>() where number%15 == 0 select number; Spec.For(onlyFifteens, x => _fizzBuzzer.Translate(x) .Equals("FizzBuzz")) .QuickCheckThrowOnFailure(); }

Page 125: Testing the Next Generation

Ok, passed 100 tests.

Page 126: Testing the Next Generation

H M M M M

Page 127: Testing the Next Generation

[TestCase] public void Classify_Values() { Spec.ForAny<int>(x => true) .Classify( x => _fizzBuzzer.Translate(x).Equals("Fizz"), "Fizz") .Classify( x => _fizzBuzzer.Translate(x).Equals("Buzz"), "Buzz") .Classify(x => _fizzBuzzer.Translate(x).Equals("FizzBuzz"), "FizzBuzz") .Classify(x => _fizzBuzzer.Translate(x) != string.Empty, "Other") .QuickCheckThrowOnFailure(); }

Page 128: Testing the Next Generation

Ok, passed 100 tests. 55% Other. 22% Fizz, Other. 13% FizzBuzz, Other. 9% Buzz, Other.

Page 129: Testing the Next Generation

H M M M M

Page 130: Testing the Next Generation

[TestCase] public void Collect_Values_For_Negatives() { Spec.ForAny<int>(x => true) .When(x => x < 0) .Collect(x => _fizzBuzzer.Translate(x)) .QuickCheckThrowOnFailure(); }

Page 131: Testing the Next Generation

Ok, passed 100 tests.

Page 132: Testing the Next Generation

G R E AT !

Page 133: Testing the Next Generation
Page 134: Testing the Next Generation
Page 135: Testing the Next Generation
Page 136: Testing the Next Generation
Page 137: Testing the Next Generation
Page 138: Testing the Next Generation
Page 139: Testing the Next Generation

http://www.specflow.org/

specflow

Page 140: Testing the Next Generation

https://github.com/fsharp/FsCheck

fscheck

Page 141: Testing the Next Generation
Page 142: Testing the Next Generation

T H A N K Y O U

Page 143: Testing the Next Generation

M I K E H A R R I S @ M I K E M K H H T T P : / / C O M P - P H I L . B L O G S P O T. C O M /