hack@macs 2014 test driven development & pair programing

Post on 06-May-2015

185 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

გიორგი მამალაძე - Test Driven Development & Pair Programming video: https://www.youtube.com/watch?v=yGg97JeyxWE

TRANSCRIPT

Test Driven Development & Pair Programing

გიორგი მამალაძე

George Mamaladze

Software Architect

Siemens I IA AS CTO

@gmamaladze

დამიწერია და გამიშვია ავტომატიზირებული

ტესტები.

ჩემს მიერ დაწერილი კოდის უმეტესობა დაფარულია ავტომატიზირებული

ტესტებით.

ტესეტების წერაზე დროს არ ვხარჯავ.

მირჩევნია კოდის წერა.

The Five Orders of Ignorance

არცოდნის 5 ხარისხი

0th Order Ignorance

რაიმეს ობიექტურად და დანამდვილებით ცოდნა

The Five Orders of Ignorance

არცოდნის 5 ხარისხი

0th Order Ignorance

რაიმეს ობიექტურად და დანამდვილებით ცოდნა

1st Order Ignorance

როდესაც იცი რომ არ იცი

The Five Orders of Ignorance

არცოდნის 5 ხარისხი

0th Order Ignorance

რაიმეს ობიექტურად და დანამდვილებით ცოდნა

1st Order Ignorance

როდესაც იცი რომ არ იცი

2nd Order Ignorance

როდესაც არ იცი რომ არ იცი

The Five Orders of Ignorance

არცოდნის 5 ხარისხი

0th Order Ignorance

რაიმეს ობიექტურად და დანამდვილებით ცოდნა

1st Order Ignorance

როდესაც იცი რომ არ იცი

2nd Order Ignorance

როდესაც არ იცი რომ არ იცი

3rd Order Ignorance

როდესაც ისიც კი არ იცი როგორ დაადგინო რომ არ იცი

The Five Orders of Ignorance

არცოდნის 5 ხარისხი

4th Order Ignorance

მაშინ როდესაც სარეთოდ წარმოდგენა არ გაქვს

Five Orders of Ignorance-ის

არცოდნის 5 ხარისხის არსებობის შესახებაც კი.

• ტესტირების ევოლუცია

• ნამდვილი Unit ტესტი

• TDD & PP

• ტესტის აგებულება და ენა

საკითხები

Q: რა ფუნქცია აქვთ ტესტებს?

A: შეცდომების (Bug-ების) პოვნა.

ტესტი დებაგერის სანაცვლოდ

ტესტირების ევოლუცია

ტესტირების გამოყოფა

მენეჯერი

პროგრამისტები

Coding

Testing

ტესტერები

ტესტირების ევოლუცია

1. Automate framework pretends to be a user

Scenario Tests

Test Driver Application

Action

Reaction

Scenario Tests

Test Driver Application SUT

Stimulus

Asserts

• Expectation 1 R

• Expectation 2 R

• Expectation 3 S

Test Result

ტესტირების ევოლუცია

1. Automate framework pretends to be a user

slow / flaky / corner cases not tested

Code Path Coverage

public void DoSomething() { readInput(); processData(); if (!isDiskFull()) { writeOutput(); } else { showError(); }; }

public void DoSomething() { readInput(); processData(); if (!isDiskFull()) { writeOutput(); } else { showError(); }; }

Happy Path

Corner Case

Code Path Coverage

ტესტირების ევოლუცია

1. Automate framework pretends to be a user

slow / flaky / corner cases not tested

2. Break down simulate dependencies

Test Driver

Break Down

Application

Step 1

Replace user with robot

Application

Data Simulator

Test Driver

Functional Tests

Step 1

Replace user with robot

Step 2

Break down and simulate

Presentation

Business Logic

Data Layer

ტესტირების ევოლუცია

1. Automate framework pretends to be a user

slow / flaky / corner cases not tested

2. Break down simulate dependencies

much faster / can simulate

ტესტირების ევოლუცია

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

ტესტირების ევოლუცია

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

ტესტირების ევოლუცია

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

ტესტირების ევოლუცია

Scenario Tests

Functional Tests

Unit Tests

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

ტესტირების ევოლუცია

ნუთუ არასაკმარისია მხოლოდ ერთი სახის

ტესტი?

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

?????

1/7 1/5 1/11 1/13

0,14 0,20 0,09 0,07 ≈ 0,51

1/2

ნამდვილი Unit test-ი

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:

რა პრობლემებთანაა დაკავშირებული Unit-

Test-ების შექმნა?

Test Driver Class Under Test

Stimulus

Asserts

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.

Test Driver

Class Under Test

Other Class

Other Class

Other Class

Object Instantiated

Object Passed In

Global Object

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

Test Driver

Class Under Test

Other Class

Other Class

Other Class

Friendly

Friendly

Friendly

Seam

Object Instantiated

Object Passed In

Global Object

Test Driver

Class Under Test

Object Instantiated

Object Passed In

Global Object

Friendly

Friendly

Friendly

Seam

Business Logic

Object Graph Construction &

Lookup

Test Driver

Class Under Test

Object Instantiated

Object Passed In

Global Object

Friendly

Friendly

Friendly

Seam

Test Driver

Class Under Test

Mock

Stub

Fake

http://www.martinfowler.com/bliki/TestDouble.html

Test

Doubles

JUnit

Code

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

TDD & PP

What is TDD?

TDD Katas

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz, 16, 17, Fizz, 19, Buzz, Fizz,

5 3

5

3

Fizz Buzz

using NUnit.Framework; [TestFixture] public class FizzBuzzTests { }

[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(); } }

[Test] public void TranslateOne() { string result = Translator.Translate(1); Assert.That(result, Is.EqualTo("1")); }

public static string Translate(int i) { return "1"; }

[Test] public void TranslateTwo() { string result = Translator.Translate(2); Assert.That(result, Is.EqualTo("2")); }

public static string Translate(int i) { return i.ToString(); }

[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(); }

[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(); }

[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(); }

[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(); }

[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(); }

[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(); }

[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(); }

[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(); }

[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(); }

[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(); }

[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; }

[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; }

[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; }

[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); }

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")]

[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; }

[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; }

TDD & PP

write failing test

write code to pass consolidate

TDD & PP

write failing test

write code to pass consolidate

TDD & PP

write failing test

write code to pass consolidate

TDD & PP

write failing test

write code to pass consolidate

TDD & PP

write failing test

write code to pass consolidate

ტესტის აგებულება და ენა

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

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); }

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

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?

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)

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

Use expressive names for your tets.

EXTREMELY EXPRESSIVE

Create your Test Language

top related