Hack@macs 2014 test driven development & pair programing

434 views

Published on

გიორგი მამალაძე - Test Driven Development & Pair Programming

video: https://www.youtube.com/watch?v=yGg97JeyxWE

  • Be the first to comment

  • Be the first to like this

Hack@macs 2014 test driven development & pair programing

  1. 1. Test Driven Development & Pair Programing გიორგი მამალაძე
  2. 2. George Mamaladze Software Architect Siemens I IA AS CTO @gmamaladze
  3. 3. დამიწერია და გამიშვია ავტომატიზირებული ტესტები.
  4. 4. ჩემს მიერ დაწერილი კოდის უმეტესობა დაფარულია ავტომატიზირებული ტესტებით.
  5. 5. ტესეტების წერაზე დროს არ ვხარჯავ. მირჩევნია კოდის წერა.
  6. 6. The Five Orders of Ignorance არცოდნის 5 ხარისხი 0th Order Ignorance რაიმეს ობიექტურად და დანამდვილებით ცოდნა
  7. 7. The Five Orders of Ignorance არცოდნის 5 ხარისხი 0th Order Ignorance რაიმეს ობიექტურად და დანამდვილებით ცოდნა 1st Order Ignorance როდესაც იცი რომ არ იცი
  8. 8. The Five Orders of Ignorance არცოდნის 5 ხარისხი 0th Order Ignorance რაიმეს ობიექტურად და დანამდვილებით ცოდნა 1st Order Ignorance როდესაც იცი რომ არ იცი 2nd Order Ignorance როდესაც არ იცი რომ არ იცი
  9. 9. The Five Orders of Ignorance არცოდნის 5 ხარისხი 0th Order Ignorance რაიმეს ობიექტურად და დანამდვილებით ცოდნა 1st Order Ignorance როდესაც იცი რომ არ იცი 2nd Order Ignorance როდესაც არ იცი რომ არ იცი 3rd Order Ignorance როდესაც ისიც კი არ იცი როგორ დაადგინო რომ არ იცი
  10. 10. The Five Orders of Ignorance არცოდნის 5 ხარისხი 4th Order Ignorance მაშინ როდესაც სარეთოდ წარმოდგენა არ გაქვს Five Orders of Ignorance-ის არცოდნის 5 ხარისხის არსებობის შესახებაც კი.
  11. 11. • ტესტირების ევოლუცია • ნამდვილი Unit ტესტი • TDD & PP • ტესტის აგებულება და ენა საკითხები
  12. 12. Q: რა ფუნქცია აქვთ ტესტებს? A: შეცდომების (Bug-ების) პოვნა.
  13. 13. ტესტი დებაგერის სანაცვლოდ
  14. 14. ტესტირების ევოლუცია
  15. 15. ტესტირების გამოყოფა მენეჯერი პროგრამისტები Coding Testing ტესტერები
  16. 16. ტესტირების ევოლუცია 1. Automate framework pretends to be a user
  17. 17. Scenario Tests Test Driver Application Action Reaction
  18. 18. Scenario Tests Test Driver Application SUT Stimulus Asserts • Expectation 1 R • Expectation 2 R • Expectation 3 S Test Result
  19. 19. ტესტირების ევოლუცია 1. Automate framework pretends to be a user slow / flaky / corner cases not tested
  20. 20. Code Path Coverage public void DoSomething() { readInput(); processData(); if (!isDiskFull()) { writeOutput(); } else { showError(); }; }
  21. 21. public void DoSomething() { readInput(); processData(); if (!isDiskFull()) { writeOutput(); } else { showError(); }; } Happy Path Corner Case Code Path Coverage
  22. 22. ტესტირების ევოლუცია 1. Automate framework pretends to be a user slow / flaky / corner cases not tested 2. Break down simulate dependencies
  23. 23. Test Driver Break Down Application Step 1 Replace user with robot
  24. 24. Application Data Simulator Test Driver Functional Tests Step 1 Replace user with robot Step 2 Break down and simulate Presentation Business Logic Data Layer
  25. 25. ტესტირების ევოლუცია 1. Automate framework pretends to be a user slow / flaky / corner cases not tested 2. Break down simulate dependencies much faster / can simulate
  26. 26. ტესტირების ევოლუცია 1. Automate framework pretends to be a user slow / flaky / corner cases not tested 2. Break down simulate dependencies much faster / can simulate still need debugging
  27. 27. ტესტირების ევოლუცია 1. Automate framework pretends to be a user slow / flaky / corner cases not tested 2. Break down simulate dependencies much faster / can simulate still need debugging 3. Break down even more
  28. 28. ტესტირების ევოლუცია 1. Automate framework pretends to be a user slow / flaky / corner cases not tested 2. Break down simulate dependencies much faster / can simulate still need debugging 3. Break down even more
  29. 29. ტესტირების ევოლუცია Scenario Tests Functional Tests Unit Tests
  30. 30. Scenario Tests Unit Tests Functional Tests # of Tests Execution Time Test individual classes / methods in isolation Test collections of classes as subsystems Tests the whole system pretending to be a user More: TestPyramid ტესტირების ევოლუცია
  31. 31. ნუთუ არასაკმარისია მხოლოდ ერთი სახის ტესტი?
  32. 32. Why should I write a unit test if we still need to have the functional one? Test Probability of deffect Cost To Run Action At Fault Flashlight 50 ??? Light Bulb 1 from 5 1 Replace Battery 1 from7 1 Replace Switch 1 from11 1 Replace Wiring 1 from 13 2 Replace ?????
  33. 33. 1/71/5 1/11 1/13 0,140,20 0,09 0,07 ≈ 0,51 1/2
  34. 34. ნამდვილი Unit test-ი
  35. 35. JUnit / NUnit ! = unit test The „real“ Unit Tests Tests that do these things aren't bad. Often they are worth writing, and they can be written in a unit test harness. However, it is important to be able to separate them from true unit tests so that we can keep a set of tests that we can run fast whenever we make our changes. Michael Feathers, "A Set of Unit Testing Rules" •It talks to the database •It communicates across the network •It touches the file system •You have to do special things to your environment (such as editing config files) to run it. •It runs longer than 0.1 second •It can't run at the same time as any of your other unit tests A test is not a unit test if:
  36. 36. რა პრობლემებთანაა დაკავშირებული Unit- Test-ების შექმნა?
  37. 37. Test Driver Class Under Test Stimulus Asserts
  38. 38. Test Driver Class Under Test Stimulus Asserts At the beginning you will realize real unit testing is hard! Your classes must be designed to be testable.
  39. 39. Test Driver Class Under Test Other Class Other Class Other Class Object Instantiated Object Passed In Global Object
  40. 40. Test Driver Class Under Test Other Class Other Class Other Class CPU Intensive Other Class Other Class Destructive operation Other Servers File System Other Class Object Instantiated Object Passed In Global Object Seam
  41. 41. Test Driver Class Under Test Other Class Other Class Other Class Friendly Friendly Friendly Seam Object Instantiated Object Passed In Global Object
  42. 42. Test Driver Class Under Test Object Instantiated Object Passed In Global Object Friendly Friendly Friendly Seam
  43. 43. Business Logic Object Graph Construction & Lookup
  44. 44. Test Driver Class Under Test Object Instantiated Object Passed In Global Object Friendly Friendly Friendly Seam
  45. 45. Test Driver Class Under Test Mock Stub Fake http://www.martinfowler.com/bliki/TestDouble.html Test Doubles JUnit Code
  46. 46. Test Doubles •Dummy objects are passed around but never actually used. •Fake objects actually have working implementations, but usually take some shortcut. •Stubs provide canned answers to calls made during the test. •Spies are stubs that also record some information based on how they were called. •Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. http://www.martinfowler.com/bliki/TestDouble.html
  47. 47. TDD & PP
  48. 48. What is TDD?
  49. 49. TDD Katas
  50. 50. 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz, 16, 17, Fizz, 19, Buzz, Fizz, 53 5 3 Fizz Buzz
  51. 51. using NUnit.Framework; [TestFixture] public class FizzBuzzTests { }
  52. 52. [Test] public void TranslateOne() { string result = Translator.Translate(1); Assert.That(result, Is.EqualTo("1")); } public class Translator { public static string Translate(int i) { throw new NotImplementedException(); } }
  53. 53. [Test] public void TranslateOne() { string result = Translator.Translate(1); Assert.That(result, Is.EqualTo("1")); } public static string Translate(int i) { return "1"; }
  54. 54. [Test] public void TranslateTwo() { string result = Translator.Translate(2); Assert.That(result, Is.EqualTo("2")); } public static string Translate(int i) { return i.ToString(); }
  55. 55. [TestCase(1, "1")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { return i.ToString(); }
  56. 56. [TestCase(1, "1")] [TestCase(2, "2")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { return i.ToString(); }
  57. 57. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { return i.ToString(); }
  58. 58. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { if (i == 3) return "Fizz"; return i.ToString(); }
  59. 59. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(6, "Fizz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { if (i == 3) return "Fizz"; return i.ToString(); }
  60. 60. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(6, "Fizz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { if (i % 3 == 0) return "Fizz"; return i.ToString(); }
  61. 61. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { if (i % 3 == 0) return "Fizz"; return i.ToString(); }
  62. 62. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { if (i % 3 == 0) return "Fizz"; if (i == 5) return "Buzz"; return i.ToString(); }
  63. 63. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { if (i % 3 == 0) return "Fizz"; if (i == 5) return "Buzz"; return i.ToString(); }
  64. 64. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] public void Translate(int input, string expected) { string result = Translator.Translate(input); Assert.That(result, Is.EqualTo(expected)); } public static string Translate(int i) { if (i % 3 == 0) return "Fizz"; if (i % 5 == 0) return "Buzz"; return i.ToString(); }
  65. 65. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] public static string Translate(int i) { if (ShouldFizz(i)) return "Fizz"; if (ShouldBuzz(i)) return "Buzz"; return i.ToString(); } private static bool ShouldBuzz(int i) { return i % 5 == 0; } private static bool ShouldFizz(int i) { return i % 3 == 0; }
  66. 66. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] [TestCase(15, "FizzBuzz")] public static string Translate(int i) { if (ShouldFizz(i)) return "Fizz"; if (ShouldBuzz(i)) return "Buzz"; return i.ToString(); } private static bool ShouldBuzz(int i) { return i % 5 == 0; } private static bool ShouldFizz(int i) { return i % 3 == 0; }
  67. 67. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] [TestCase(15, "FizzBuzz")] public static string Translate(int i) { string returnString = string.Empty; if (ShouldFizz(i)) returnString += "Fizz"; if (ShouldBuzz(i)) returnString += "Buzz"; if (string.IsNullOrEmpty(returnString)) { returnString = i.ToString(); } return returnString; }
  68. 68. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] [TestCase(15, "FizzBuzz")] public static string Translate(int i) { string returnString = string.Empty; returnString = Fizzy(i, returnString); if (ShouldBuzz(i)) returnString += "Buzz"; if (string.IsNullOrEmpty(returnString)) { returnString = i.ToString(); } return returnString; } private static string Fizzy(int i, string returnString) { return returnString + (ShouldFizz(i) ? "Fizz" : string.Empty); }
  69. 69. public static string Translate(int i) { string returnString = string.Empty; returnString = Fizzy(i, returnString); returnString = Buzzy(i, returnString); if (string.IsNullOrEmpty(returnString)) { returnString = i.ToString(); } return returnString; } private static string Buzzy(int i, string returnString) { return returnString + (ShouldBuzz(i) ? "Buzz" : string.Empty); } [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] [TestCase(15, "FizzBuzz")]
  70. 70. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] [TestCase(15, "FizzBuzz")] public static string Translate(int i) { string returnString = string.Empty; returnString = Fizzy(i, returnString); returnString = Buzzy(i, returnString); returnString = Other(i, returnString); return returnString; } private static string Other(int i, string returnString) { return string.IsNullOrEmpty(returnString) ? i.ToString() : returnString; }
  71. 71. [TestCase(1, "1")] [TestCase(2, "2")] [TestCase(3, "Fizz")] [TestCase(5, "Buzz")] [TestCase(6, "Fizz")] [TestCase(10, "Buzz")] [TestCase(15, "FizzBuzz")] public static IList<Func<int, string, string>> Rules = new List<Func<int, string, string>> { Fizzy, Buzzy, Other }; public static string Translate(int i) { string returnString = string.Empty; foreach (var rule in Rules) { returnString = rule(i, returnString); } return returnString; }
  72. 72. TDD & PP write failing test write code to passconsolidate
  73. 73. TDD & PP write failing test write code to passconsolidate
  74. 74. TDD & PP write failing test write code to passconsolidate
  75. 75. TDD & PP write failing test write code to passconsolidate
  76. 76. TDD & PP write failing test write code to passconsolidate
  77. 77. ტესტის აგებულება და ენა
  78. 78. Cyclomatic complexity of 1 (no conditionals) Containing three sections Prepare: Declaration and initialization Do: Do actual work – invoke the member under test. Assert: Assert execution results. The Structure of a Unit Test
  79. 79. In ideal case every test contains exactly tree lines: The Structure of a Unit Test Terminology: •Target (target) •Source data •Expectation (expected) •Actual result (actual) [Test] public void Test(...) { var target = TargetFactory.Create(sourceData); var actual = target.DoSomething(); Assert.AreEqual(expected, actual); }
  80. 80. Create your Test Language „The language you write test code is not the language you write your productive code.“ • Custom assertion library • Test data factory • Expressive names • One assertion per test • Cyclomatic complexity ==1 • 3 Lines rule
  81. 81. Assertion * String lenghts differ… * Expected: True but was: False Etc. Our goal is to find an error without much debugging. Let the failed test supply us with following information: 1. Which method was tested? 2. What was the intention of test? 3. What’s gone wrong exactly?
  82. 82. Assertion Let your asserst tell you the truth! Failed: Clear_removes_all_elements_from_collection Expected number of elements 0 but was 1 Expected True but was False at (0,0)
  83. 83. Factory vs Build-up Code Test Case Factories are classes which produce complex test object trees based on very few simple parameters. Simple means - simple to write & simple to read. TreeFactory.BuildTree(„a[b1,b2,b3[c1,c2,c3]]“) a b1 b2 b3 c1 c2 c3
  84. 84. Use expressive names for your tets. EXTREMELY EXPRESSIVE Create your Test Language

×