[Tech talk] testing for the skeptical developer (tdd, bdd & other)

59
Testing for the skeptical developer Andrei Sebastian Cîmpean, 2016

Transcript of [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Page 1: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Testing for the skeptical developerAndrei Sebastian Cîmpean, 2016

Page 2: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Acceptance testing

performed to verify that the product is acceptable to the customer and if it's fulfilling the specified requirements

Unit testing

it tests a unit of the program as a whole

Page 3: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Common excuses

➔ It’s slowing me down...

➔ It wasn’t done from the start of the project...

➔ The client doesn’t pay for it…

➔ It’s not worth it / I’m testing my code before push

➔ We have QA

➔ IT’S HARD

➔ I’M AFRAID

Page 4: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Unit test ➔ What is a unit test➔ Types of unit tests

Page 5: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Unit tests

➔ Low-level, focusing on a small part of the software system

➔ Significantly faster than other kinds of tests

➔ Written by the programmers that implement the features

➔ Can be run very frequently when programming

Page 6: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Unit testAccording to the definition on wikipedia a unit can be an individual method, but it can also be something much larger that likely includes many collaborating classes.

Unit testing is an umbrella name for testing at a certain level of abstraction.

Page 7: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

From http://learnrubythehardway.org/book/ex47.html

Page 8: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

A test suite that isn’t run regularly doesn’t have many opportunities to provide positive ROI.

Page 9: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Test doubles➔ Dummy➔ Fake➔ Stubs➔ Spies➔ Mocks

“It’s hard”“It’s slowing me down”

Page 10: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Dummy objects are passed around but never actually used.

Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production.

Stubs provide canned answers to calls made during the test. Stubs may also record information about calls.

Mocks are objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Page 11: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Mocks (and mock expectations) are fake methods (like spies) with pre-programmed behavior (like stubs) as well as pre-programmed expectations.

The rule of thumb is: if you wouldn’t add an assertion for some specific call, don’t mock it.

Page 12: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Types of tests ➔ That check state➔ That check

behaviour

Page 13: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

State verificationDescribes a style of testing where you exercise one or many methods of an object and then assert the expected state of the object (and/or collaborators).

Movie movie = a.movie.build();

Rental rental = a.rental.w(movie).build();

Store store = a.store.w(movie).build();

rental.start(store);

assertTrue(rental.isStarted());

assertEquals(0, store.getAvailability(movie));

Page 14: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

State verification tests specify the least possible implementation detail, thus they will continue to pass even if the internals of the methods being tested are changed.

Page 15: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Behaviour verificationDescribes a style of testing where the execution of a method is expected to generate specific interactions between objects.

Movie movie = a.movie.build();

Rental rental = a.rental.w(movie).build();

Store store = mock(Store.class);

when(store.getAvailability(movie))

.thenReturn(1);rental.start(store);

assertTrue(rental.isStarted());

Page 16: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

➔ Implementation changes that preserve macro behavior can lead to difficult to understand and largely valueless test failures.

➔ Behavior verification tests with minimal collaborators can effectively verify interactions without sacrificing maintainability.

➔ A team that relies on Behavior verification will likely produce a codebase with few Law of Demeter violations and a focus on Tell, Don’t Ask.

Page 17: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Law of Demeter Only talk to your immediate friends

Tell, Don’t AskRather than asking an object for data and acting on that data, we should instead tell an object what to do

Page 18: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Types of tests ➔ Solitary➔ Sociable

Page 19: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Solitary Unit Test Test methods of a class, or

functions of a namespace, to validate that they behave as expected.

Page 20: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Pure functionsA function where the return value is only determined by its input values, without observable side effects.

Page 21: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

ConstraintsNever cross boundaries➔ Boundary crossing increases the fragility and execution time of your test

suite➔ Examples:

◆ interacting with a database◆ interacting with the filesystem◆ interacting with time

Page 22: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

ConstraintsThe Class Under Test should be the only concrete class found in a test➔ Use a double for dependencies.➔ Collaborators that return objects should return doubles.➔ No statics.➔ Doesn’t apply to primitives or classes with literals

Page 23: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Sociable Unit TestUnit tests that are not solitary, are sociable ...

Page 24: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

There are two primary reasons for writing Solitary Unit Tests:

Sociable Unit Tests can be slow and nondeterministic

Sociable Unit Tests are more susceptible to cascading failures

Page 25: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

From http://slidedeck.io/josephdpurcell/principles-of-solitary-unit-testing

$stub = $this->getMockBuilder(‘User’)->getMock();$stub->method(‘getFirstName’)->willReturn(‘First’);$stub->method(‘getLastName’)->willReturn(‘Last’);$cut = new ClassUnderTest($stub);

$fullName = $cut->getFullName();

$this->assertEquals(‘First Last’, $fullName’);

Solitary unit test using stubs

Page 26: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Test DrivenDevelopment

➔ Breaking a problem up into smaller pieces

➔ Defining the “simplest thing that could possibly work”

➔ Improved design

Page 27: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

It’s not necessary to write unit tests to do TDD.

It’s not necessary to do TDD to write unit tests.

Page 28: [Tech talk] testing for the skeptical developer (tdd, bdd & other)
Page 29: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

What is TDD according to WikipediaA development process that relies on the repetition of a very short development cycle:

1.The developer writes an (initially failing) automated test case that defines a desired improvement or new function

2.The developer produces the minimum amount of code to pass that test

3.The developer refactors the new code to acceptable standards

Page 30: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Write failing test

from https://www.codementor.io/nodejs/tutorial/unit-testing-nodejs-tdd-mocha-sinon

Page 31: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Write failing test

from https://www.codementor.io/nodejs/tutorial/unit-testing-nodejs-tdd-mocha-sinon

Page 32: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Write just enough code to pass the test

from https://www.codementor.io/nodejs/tutorial/unit-testing-nodejs-tdd-mocha-sinon

Page 33: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Write just enough code to pass the test

from https://www.codementor.io/nodejs/tutorial/unit-testing-nodejs-tdd-mocha-sinon

Page 34: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Write failing test

from https://www.codementor.io/nodejs/tutorial/unit-testing-nodejs-tdd-mocha-sinon

Page 35: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Write failing test

from https://www.codementor.io/nodejs/tutorial/unit-testing-nodejs-tdd-mocha-sinon

Page 36: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Write just enough code to pass the test

from https://www.codementor.io/nodejs/tutorial/unit-testing-nodejs-tdd-mocha-sinon

Page 37: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

“As the tests get more

specific, the code gets

more generic”

As a test suite grows, it becomes a more detailed specification of behavior.

Developers should meet this increase in specification by increasing the generality of their code.

Robert C. Martin

Page 38: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Specific tests lead to generic production codeEvery new test case makes the test suite more constrained and more specific.

Just adding if statements ...

Page 39: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Specific tests lead to generic production codeEvery new test case makes the test suite more constrained and more specific.

Just adding if statements will not work in the long run. Developers end up making tests pass by innovating general algorithms.

To make the new test case pass, the programmer strives to make the production code more general, not more specific.

Page 40: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

➔ Programmers deserve to feel confident that their code works and TDD is one (not the only) way to reach that

➔ Tackle problems piecemeal, figuring out specific cases without having to solve the general case all at once

➔ Leads to more modularized, flexible, and extensible code

➔ Existing tests provide a safety net

➔ Confusion over the definition of TDD and unit testing

➔ Many people make bad trade-offs, especially with heavy mocking that end up driving architecture

➔ “HARDER”

Page 41: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

➔ TDD gives a mechanism to quickly get feedback on an idea and example usage of an API while implementing it one step at a time.

➔ Can be very appealing to developers who can find a large problem overwhelming

➔ Programmers are able to focus exclusively on the task at hand: make the individual test pass

➔ TDD is may leave you uncertain what exactly to do with the Refactor phase.

Page 42: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Behaviour Driven

Development

➔ An executable specification that fails because the feature doesn't exist

➔ Writing the simplest code that can make the spec pass.

➔ Repeat this until a release candidate is ready to ship.

➔ Easier to read TDD?

Page 43: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Behavior-driven development is facilitated by a simple domain-specific language (DSL) using natural language constructs (e.g., English-like sentences) that can express the behavior and the expected outcomes.

BDD suggests that unit test names be whole sentences starting with a conditional verb ("should" in English for example).

BDD suggests that unit tests should be written in order of business value.

from https://en.wikipedia.org/wiki/Behavior-driven_development#Behavioural_specifications

Page 44: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

from https://thomassundberg.wordpress.com/2014/05/29/cucumber-jvm-hello-world/

file: Belly.feature file: StepDefinitions.java

Page 45: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

So if we write tests in a BDD style ...

1. Customers can read them2. Customers can give us

early feedback3. Customers can write some

of them

Page 46: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

So if we write tests in a BDD style ...

1. Customers can read them2. Customers can give us

early feedback3. Customers can write some

of themThis never* happens

Page 47: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Since BDD is basically is feature driven approach to TDD, there is value in doing it if you want to.

Page 48: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

NodeJS acceptance test

Page 49: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

from http://gregbabiars.com/acceptance-testing-a-react-app-using-react-test-utils-pretender-and-rxjs/

Page 50: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

To explore for better tests➔ Stick to one assertion per test (maintainability)➔ The assertion should be the last piece of code found within a test➔ Negative testing➔ Global day of coderetreat

➔ Test only public methods *

Page 51: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Test only public methodsPublic methods are a contract. They do not change.

Private methods are the implementation details. They are subject to change.

It’s OK to write temporary tests for private methods while you’re exploring the implementation but you should remove them before commit.

Page 52: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Common excuses

again...

➔ It’s slowing me down...

➔ It wasn’t done from the start of the project...

➔ The client doesn’t pay for it…

➔ It’s not worth it / I’m testing my code before push

➔ We have QA

➔ IT’S HARD

➔ I’M AFRAID

Page 53: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Writing tests is slowing me down...

Page 54: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Strategies for working with legacy codeAll new code is tested.

Black Box untested code. Don’t work directly with untested code but use specialized objects that know how to do that

Read: http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

Page 55: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Not paid to write testsYou’re not paid to write tests, you just write enough to be confident that your code works as required.

Refactoring without having unit tests is not refactoring, it’s moving code around.

You don't have enough tests (or good enough tests) if you can't confidently change the code. In the other extreme, not changing code because you

Page 56: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Things to consider when setting up an environment

Frequency - how rapidly do we want our feedback ?

Fidelity - how accurate do we want the red/green signal to be?

Overhead - how much are we prepared to pay?

Lifespan - how long is this software going to be around?

Page 57: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Other benefits to doing testing➔ Easier ramp-up for newcomers on the project or feature

➔ Code reuse is encouraged

➔ Developer uses the code as a client would

Page 58: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

“Mocks Aren’t Stubs”, Martin Fowler

“UnitTest”, Martin Fowler

“Is TDD dead?”, Kent Beck, David Heinemeier Hansson, Martin Fowler

"Working Effectively With Unit Tests", Jay Fields

“Test Driven Development”

Page 59: [Tech talk] testing for the skeptical developer (tdd, bdd & other)

Q & AWould you rather throw away the code and keep the tests or vice-versa?

How do you know if your code-base is healthy?