TDD and the Terminator

Ac87ebf0cf6b8e9f4e66582ec9845620?s=47 Layla Porter
September 05, 2019

TDD and the Terminator

Getting started with Test Driven Development (TDD) can be very challenging. It requires a different mindset and approach to writing and developing code. However, once in that mindset, it is very difficult not to write tests first.

But why bother writing tests first?

In this session, we will go through the reasons for writing tests before coding, look at architecture and design principles, such as SOLID and see how it all comes together to create a more testable and maintainable application.

I will show you how to get started writing tests first with practical examples on how to reprogram a T800 series Terminator so you can start using TDD in your own applications (or killer robots from the future).

Hasta La Vista badly-written code!

Ac87ebf0cf6b8e9f4e66582ec9845620?s=128

Layla Porter

September 05, 2019
Tweet

Transcript

  1. @LaylaCodesIt

  2. @LaylaCodesIt

  3. @LaylaCodesIt MICROSOFT MVP MK .NET ORGANISER C# LOVER DEVELOPER EVANGELIST

    @ LAYLA PORTER
  4. @LaylaCodesIt WHY TDD AND THE TERMINATOR?

  5. @LaylaCodesIt TDD SUCCESSES •Acceptance Criteria •Focus •Interfaces •Asynchronous development •Cleaner

    code •Safe refactoring •Fewer bugs •Increasing returns •Living documentation
  6. @LaylaCodesIt BACK TO THE TERMINATOR

  7. @LaylaCodesIt THE PROCESS

  8. @LaylaCodesIt GATHER THE REQUIREMENTS

  9. @LaylaCodesIt

  10. @LaylaCodesIt Terminator Requirements Scan subjects and determine if they require

    further investigation Investigate subjects of interest and determine if they are the target - TERMINATE!
  11. @LaylaCodesIt Scan subjects and determine if they require further investigation

  12. @LaylaCodesIt START WITH FAILING TESTS

  13. @LaylaCodesIt When you write tests after coding you may be

    writing them to fit your code and not your requirements
  14. @LaylaCodesIt RED/GREEN REFACTOR PATTERN • Write a failing test •

    Write enough code to get the test to pass • Refactor!
  15. @LaylaCodesIt OVER TO CODE

  16. @LaylaCodesIt REFACTOR!

  17. @LaylaCodesIt public bool InvestigateFurther(ISubject subject) { if (subject.SubjectName.ToLower() ==" "woman")

    { return true; } if (subject.SubjectName.ToLower() ==" "girl") { return true; } if (subject.SubjectName.ToLower() ==" "man") { return true; } if (subject.SubjectName.ToLower() ==" "boy") { return true; } return false; }
  18. @LaylaCodesIt public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case

    "woman": case "girl": case "man": case "boy": return true; default: return false; } } public bool InvestigateFurther(ISubject subject) { if (subject.SubjectName.ToLower() ==" "woman") { return true; } if (subject.SubjectName.ToLower() ==" "girl") { return true; } if (subject.SubjectName.ToLower() ==" "man") { return true; } if (subject.SubjectName.ToLower() ==" "boy") { return true; } return false; }
  19. @LaylaCodesIt public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case

    "woman": case "girl": case "man": case "boy": return true; default: return false; } } [TestCase("woman")] [TestCase("girl")] [TestCase("man")] [TestCase("boy")] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName) { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Should().BeTrue(); } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); }
  20. @LaylaCodesIt public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case

    "woman": case "girl": case "man": case "boy": return true; default: return false; } } [TestCase("woman")] [TestCase("girl")] [TestCase("man")] [TestCase("boy")] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName) { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Should().BeTrue(); } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); }
  21. @LaylaCodesIt REQUIREMENT CHANGE!

  22. @LaylaCodesIt

  23. @LaylaCodesIt New Terminator Requirements Protect John and Sarah Connor from

    threats Ability to learn
  24. @LaylaCodesIt public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case

    "woman": case "girl": case "man": case "boy": return true; default: return false; } } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); } TerminatorShould_DetermineNot_ToInvestigateFurther("T1000"): Success
  25. @LaylaCodesIt public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case

    "woman": case "girl": case "man": case "boy": case "T1000": return true; default: return false; } } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); } TerminatorShould_DetermineNot_ToInvestigateFurther("T1000"): Failed: Expected result to be False, but found True
  26. @LaylaCodesIt DESIGNING YOUR APPLICATION TO BE MORE ROBUST

  27. @LaylaCodesIt DESIGN PATTERNS

  28. @LaylaCodesIt DESIGN PATTERNS SOLID PRINCIPLES

  29. @LaylaCodesIt EPENDENCY INVERSION PRINCIPLE S O I D L NTERFACE

    SEGREGATION PRINCIPLE ISKOV SUBSTITUTION PRINCIPLE PEN/CLOSE PRINCIPLE INGLE RESPONSIBILITY PRINCIPLE
  30. @LaylaCodesIt EPENDENCY INVERSION PRINCIPLE S O I D L NTERFACE

    SEGREGATION PRINCIPLE ISKOV SUBSTITUTION PRINCIPLE PEN/CLOSE PRINCIPLE INGLE RESPONSIBILITY PRINCIPLE
  31. @LaylaCodesIt Every class or module in a program should have

    responsibility for just a single piece of that program's functionality. SINGLE RESPONSIBILITY PRINCIPLE
  32. @LaylaCodesIt Software entities (classes, modules, functions, etc.) should be open

    for extension, but closed for modification. OPEN/CLOSE PRINCIPLE
  33. @LaylaCodesIt Objects should be replaceable with instances of their subtypes

    without altering the correctness of that program. LISKOV SUBSTITUTION PRINCIPLE LET'S SEE IT IN ACTION!
  34. @LaylaCodesIt REFACTOR!

  35. @LaylaCodesIt [TestCase("woman")] [TestCase("girl")] [TestCase("man")] [TestCase("boy")] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName)

    { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Should().BeTrue(); } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); }
  36. @LaylaCodesIt [TestCase("woman")] [TestCase("girl")] [TestCase("man")] [TestCase("boy")] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName)

    { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Should().BeTrue(); } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); } [TestCase("woman", true)] [TestCase("girl", false)] [TestCase("man", false)] [TestCase("boy",true)] [TestCase("T1000",true)] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName, bool outcome) { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Equals(outcome); }
  37. @LaylaCodesIt [TestCase("woman")] [TestCase("girl")] [TestCase("man")] [TestCase("boy")] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName)

    { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Should().BeTrue(); } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); } [TestCase("woman", true)] [TestCase("girl", false)] [TestCase("man", false)] [TestCase("boy",true)] [TestCase("T1000",true)] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName, bool outcome) { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Equals(outcome); }
  38. @LaylaCodesIt [TestCase("woman")] [TestCase("girl")] [TestCase("man")] [TestCase("boy")] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName)

    { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Should().BeTrue(); } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); } [TestCase("woman", true)] [TestCase("girl", false)] [TestCase("man", false)] [TestCase("boy",true)] [TestCase("T1000",true)] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName, bool outcome) { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Equals(outcome); }
  39. @LaylaCodesIt [TestCase("woman")] [TestCase("girl")] [TestCase("man")] [TestCase("boy")] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName)

    { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Should().BeTrue(); } [Test] public void TerminatorShould_DetermineNot_ToInvestigateFurther() { var subject = new Subject {SubjectName = "T1000"}; var result = _sut.InvestigateFurther(subject); result.Should().BeFalse(); } [TestCase("woman", true)] [TestCase("girl", false)] [TestCase("man", false)] [TestCase("boy",true)] [TestCase("T1000",true)] public void TerminatorShould_Determine_ToInvestigateFurther (string subjectName, bool outcome) { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Equals(outcome); }
  40. @LaylaCodesIt [TestCase("woman", true)] [TestCase("girl", false)] [TestCase("man", false)] [TestCase("boy",true)] [TestCase("T1000",true)] public

    void TerminatorShould_Determine_ToInvestigateFurther(string subjectName, bool outcome) { var subject = new Subject {SubjectName = subjectName}; var result = _sut.InvestigateFurther(subject); result.Equals(outcome); } TerminatorShould_Determine_ToInvestigateFurther (5 tests) Success TerminatorShould_Determine_ToInvestigateFurther("T1000",True) Success TerminatorShould_Determine_ToInvestigateFurther("man",False) Success TerminatorShould_Determine_ToInvestigateFurther("girl",False) Success TerminatorShould_Determine_ToInvestigateFurther("boy",True) Success TerminatorShould_Determine_ToInvestigateFurther("woman",True) Success
  41. @LaylaCodesIt public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case

    "woman": case "girl": case "man": case "boy": case "T1000": return true; default: return false; } } public interface ISubject { string SubjectName { get; set; } } public class Subject : ISubject { public string SubjectName { get; set; } }
  42. @LaylaCodesIt public interface ISubject { string SubjectName { get; set;

    } } public class Subject : ISubject { public string SubjectName { get; set; } } public interface ISubjectRule { bool IsMatch(Subject subject); bool OfInterest(); } public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case "woman": case "girl": case "man": case "boy": case "T1000": return true; default: return false; } }
  43. @LaylaCodesIt public class IsWomanRule : ISubjectRule { public bool OfInterest()

    { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case "woman": case "girl": case "man": case "boy": case "T1000": return true; default: return false; } }
  44. @LaylaCodesIt public class IsWomanRule : ISubjectRule { public bool OfInterest()

    { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } } public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case "woman": case "girl": case "man": case "boy": case "T1000": return true; default: return false; } }
  45. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public bool InvestigateFurther(ISubject subject) { switch (subject.SubjectName.ToLower()) { case "woman": case "girl": case "man": case "boy": case "T1000": return true; default: return false; } }
  46. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  47. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  48. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  49. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  50. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  51. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  52. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  53. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  54. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  55. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  56. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class IsWomanRule : ISubjectRule { public bool OfInterest() { return true; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("woman"); } } public class IsDogRule : ISubjectRule { public bool OfInterest() { return false; } public bool IsMatch(Subject subject) { return subject.SubjectName.ToLower().Contains("dog"); } }
  57. @LaylaCodesIt If you need to make a private method public

    in order to test it, then it's time to refactor
  58. @LaylaCodesIt public SubjectAnalysisService() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule());

    _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch =_subjectRules.FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } TerminatorShould_Determine_ToInvestigateFurther (5 tests) Success TerminatorShould_Determine_ToInvestigateFurther("dog",False) Success TerminatorShould_Determine_ToInvestigateFurther("woman",True) Success
  59. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser private readonly List<ISubjectRule> _subjectRules;

    public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule> _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } }
  60. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); _subjectRules.Add(new IsBoyRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule> _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } }
  61. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); _subjectRules.Add(new IsBoyRule()); _subjectRules.Add(new IsManRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule> _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } }
  62. @LaylaCodesIt public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule>

    _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); _subjectRules.Add(new IsBoyRule()); _subjectRules.Add(new IsManRule()); _subjectRules.Add(new IsT1000Rule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } } public class SubjectAnalyser : ISubjectAnalyser { private readonly List<ISubjectRule> _subjectRules; public SubjectAnalyser() { _subjectRules = new List<ISubjectRule>(); _subjectRules.Add(new IsWomanRule()); _subjectRules.Add(new IsDogRule()); } public bool InvestigateFurther(Subject subject) { var isMatch = _subjectRules .FirstOrDefault(r =>$ r.IsMatch(subject)); return isMatch ==" null || Investigate(isMatch); } private bool Investigate(ISubjectRule rule) { return rule.OfInterest(); } }
  63. @LaylaCodesIt WITH GOOD PRACTICES, CODE MANAGEMENT BECOMES INFINITELY EASIER

  64. @LaylaCodesIt TDD FAILURES •Underestimating the learning curve •Confusing TDD with

    unit testing •Thinking TDD is enough testing •Not starting with failing tests •Not refactoring enough •Not actually doing TDD!
  65. @LaylaCodesIt IMPLEMENTATION WITHIN YOUR ORGANIZATION •Can be controversial and is

    a significant culture change •Initial drop in productivity can be disconcerting •Productivity will go up and reworks reduced •Increased understanding of requirements and their acceptance criteria
  66. @LaylaCodesIt

  67. @LaylaCodesIt

  68. @LaylaCodesIt IF YOU TAKE ONE THING AWAY FROM THIS TALK...

  69. @LaylaCodesIt [Test] public void TerminatorShould_Determine_ToInvestigateFurther (ISubject subject) { var subject

    = new Subject{SubjectName = "woman"}; var result = _sut.InfestigateFurther(subject); result.Should().BeTrue(); }
  70. @LaylaCodesIt [Test] public void TerminatorShould_Determine_ToInvestigateFurther (ISubject subject) { var subject

    = new Subject{SubjectName = "woman"}; var result = _sut.InfestigateFurther(subject); result.Should().BeTrue(); } public bool _sut.InvestigateFurther(ISubject subject) { return true; }
  71. @LaylaCodesIt [Test] public void TerminatorShould_Determine_ToInvestigateFurther (ISubject subject) { var subject

    = new Subject{SubjectName = "woman"}; var result = _sut.InfestigateFurther(subject); result.Should().BeTrue(); } public bool _sut.InvestigateFurther(ISubject subject) { return true; } Write the least amount of code to get your test to pass. Return true!
  72. @LaylaCodesIt Twitter: @LaylaCodesIt GitHub: Layla-P Email: lporter@twilio.com Repo: http://bit.ly/tdd-terminator Deck:

    http://bit.ly/tdd-deck