Writing Tests
Effectively
Codeweavers Development Series
Introduction
What do we actually mean by Unit Test?
Why we write tests
Approaches to writing tests
What we can do going forward
2
Unit Test Definition
In computer programming, unit testing is a software testing method by which individual
units of source code, sets of one or more computer program modules together with
associated control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Intuitively, one can view a unit as the smallest
testable part of an application. In procedural programming, a unit could be an entire
module, but it is more commonly an individual function or procedure. In object-oriented
programming, a unit is often an entire interface, such as a class, but could be an
individual method.
Unit Testing - Wikipedia
3
How big is a Unit Test
It depends…
4
How big is a Unit Test
● OO Languages
○ Test at method level
○ Test Fixture per class
■ 1 to Many for every method
5
How big is a Unit Test
● Functional
○ One test module for every domain
○ One to many tests for each function
6
Why Test?
Or rather, why don’t people write tests?
● No Time to write tests
○ Probably because you’re spending so long debugging
● Tests that add value haven’t been written
○ How can we do this?
7
Why Test?
● Be playful!
○ Experiment!
● Can play around in your test framework
● Gain huge confidence in your codebase
8
Who are we testing for?
2 Approaches
● Write Unit Tests for yourself
○ How would you want to maintain it?
● Put the team first
○ They can extend your code with confidence
○ Provide your team with guidelines to work to
9
...
Still not convinced?
10
Unit Tests are a waste of time!
Unit Tests are a waste of time
● Are writing tests making you more productive?
○ If not then stop writing them!
● Kill wasteful tests
○ You want plenty of unit tests that are really helpful!
○ Keep test suites quick to keep them useful
■ 10 second test suites?!?
11
Unit Tests are a waste of time
Maybe invest in writing better Unit Tests?
12
Unit Tests are easy!
● Easy to write
○ Easy to write poorly
● What do we do wrong?
○ Strongly couple our tests to our code
○ Thinking about yourself
○ Not getting ‘Bang for the bucks’
13
TDD vs Unit Tests
Not the same thing!
14
TDD vs Unit Tests
A test you wrote to do TDD may not be
valuable for you in the long term
Just because a test was useful to help you
create a feature doesn’t mean it needs to
stay
15
TDD vs Unit Tests
● Maybe the test doesn’t add value
○ What is the ROI on having this test?
○ How many phone calls does it prevent?
● Maybe deleting it isn’t right but…
○ How about making it more useful?
16
TDD vs Unit Tests
● If this test was failing right now what clues
would you want it to give you to help you
solve the issue faster
○ Work together to find out what that is and then
change your test accordingly
○ Test goes from helping you deliver to helping you
maintain value
17
TDD
● TDD is a technique to help you write code
and defining a nice way to use it
○ Not necessarily a good way to ensure that feature is
well tested if it even needs lots of tests at all
○ How much time will be spent maintaining the tests?
18
Approachability
● Let’s imagine a 6 month old failing test
○ What clues does it give me?
○ Does it explain the domain?
○ How much test code do you have to wade through to
find out what it does?
○ Is it DRY?
■ This doesn’t mean the least characters possible…
19
Let’s talk about DRY
● Often see a broken test that is unrelated
○ Wouldn’t it be great if you could quickly see what
was going on...
○ Then you wouldn’t be so annoyed!
Repeating yourself to help others
understand what is going on is probably a
good idea 20
Let’s talk about DRY
Apply DRY on a test suite level
Apply DRY on a single test
21
Let’s talk about DRY
● In a group of tests you can repeat things
○ What happens when 2 out of 5 tests in a test fixture
fail?
○ Duplication can lead to more maintainable tests
○ Always ask what is the value of the test?
22
Data Builders
● Avoid using ObjectMother pattern
○ Breaks down when needing different data
○ Personas -> Bob & Jane both have different attributes
● Create data builders - Nat Pryce
○ http://www.natpryce.com/articles/000714.html
23
Some things to avoid
● Avoid
○ Looping
○ Language Constructs
○ Reflection
Stay in domain code as much as possible
24
Maintainability
Tests should be just as maintainable as the rest
of the codebase
We don’t need to approach writing tests in
quite the same way as production code
25
Different Thinking
Approach tests in a way where readability is
more important than performance
Milliseconds don’t matter (probably)
However, test suites need to be fast!
26
Too many tests
● Too many tests… not enough tests…
○ Both are suboptimal
● Not enough then too long spent debugging
● Too many then too long to run and maintain
○ Both lead to WASTE
27
Code Coverage
● Useful!
● Not looking for 100% code coverage
○ End up doing random things like testing getters and
setters
○ Don’t have to test third party libraries
28
What to test?
The most complex parts of the system that add
the most value
Lots of tests in Allium for example
Maybe too many?
29
Test different things
● What different types of tests?
○ Fast tests - mock things out
○ Database tests - slow but useful?
○ Etc.
Want test suite to be fast but depends on needs
● Maybe you need one database test per suite?
30
Test Categories
● State Verification
○ Check the state of the system after it has been
exercised and compare it to the expected state
■ e.g. Assert.AreEqual(a, b)
● Set up -> Call a function -> Check result
31
Test Categories
● Behaviour Verification
○ Capture the indirect outputs of the test as they occur
and compare them to the expected behaviour
● Mock out -> Verify behaviour happens
32
Test Categories
● Both are fine!
○ Consider and think which style suits you or the
situation best
● Probably a combination of both
33
Unit Tests
● Solitary Unit Test
○ Tests that don’t cross boundaries
○ Test a single class at a time
● e.g. Library -> Book
○ Library tests still pass if book changes
34
Unit Tests
● Sociable Unit Test
○ Tests that cross boundaries
○ Test multiple classes at a time
● e.g. Library -> Book
○ Library tests fail if book changes.
35
Unit Tests
● Cascading failures can occur with sociable
tests
○ Solitary tests prevent this happening
36
COMBO TIME
● Write lots of solitary unit tests
○ As many as you can
● One or two sociable unit tests
○ Makes sure that things work together but don't need
to test edge cases with slow sociable tests
37
Stub vs Mock
● Mock used in Behaviour based tests
○ For Verification
● Stub you don’t verify
○ Return canned responses
38
Going away
● Write lots of fast solitary tests
○ With a few sociable ones too
● Keep your tests approachable
● Keep your tests maintainable
○ Don’t freak out by breaking some of the production
code rules to achieve these
39
Going away
● Make expected literals
○ Don’t call method for expected values
○ Convert objects to literals or write custom assertions
(that are also tested) - Think Money object
● Get rid of loops
○ Split into individual tests
40
Going away
● Don’t use reflection
○ Being clever in tests isn’t a good idea
○ Avoiding LINQ might be a good idea too
● Use Data Builders
○ Don’t use Object Mother pattern
41
More controversial
● 1 assertion per unit test rule
● Get rid of setup methods
○ Failing tests don’t alert you to go look in the setup
○ Write whole story in the tests
42
Higher Level Tests
Also useful
Such as Integration tests
Unit Tests are just the beginning...
43
Higher Level Tests
44
How long should you spend?
● 50/50?
● Write Tests -> Write Simplest Thing ->
Refactor Test
○ Spending longer on tests then?
○ Don’t test everything though so probably not more
time
45
How long should you spend?
● Anything between 30 and 50% time - unless
your TDDing and then deleting so maybe
longer as TDD is part of design phase
● Basically, however long you need to!
46
Wrap up
● Don’t give up on tests
● Look for ways to improve ROI in writing tests
○ Keep reading - Blogs, Books, Podcasts
47
Reading
Working Effectively with Unit Tests
https://www.goodreads.com/book/show/22605938-working-effectively-with-unit-tests
Growing Object-Oriented Software
https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests
Nat Pryce - Data Builders
http://www.natpryce.com/articles/000714.html
48

Writing Tests Effectively

  • 1.
  • 2.
    Introduction What do weactually mean by Unit Test? Why we write tests Approaches to writing tests What we can do going forward 2
  • 3.
    Unit Test Definition Incomputer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use. Intuitively, one can view a unit as the smallest testable part of an application. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method. Unit Testing - Wikipedia 3
  • 4.
    How big isa Unit Test It depends… 4
  • 5.
    How big isa Unit Test ● OO Languages ○ Test at method level ○ Test Fixture per class ■ 1 to Many for every method 5
  • 6.
    How big isa Unit Test ● Functional ○ One test module for every domain ○ One to many tests for each function 6
  • 7.
    Why Test? Or rather,why don’t people write tests? ● No Time to write tests ○ Probably because you’re spending so long debugging ● Tests that add value haven’t been written ○ How can we do this? 7
  • 8.
    Why Test? ● Beplayful! ○ Experiment! ● Can play around in your test framework ● Gain huge confidence in your codebase 8
  • 9.
    Who are wetesting for? 2 Approaches ● Write Unit Tests for yourself ○ How would you want to maintain it? ● Put the team first ○ They can extend your code with confidence ○ Provide your team with guidelines to work to 9
  • 10.
    ... Still not convinced? 10 UnitTests are a waste of time!
  • 11.
    Unit Tests area waste of time ● Are writing tests making you more productive? ○ If not then stop writing them! ● Kill wasteful tests ○ You want plenty of unit tests that are really helpful! ○ Keep test suites quick to keep them useful ■ 10 second test suites?!? 11
  • 12.
    Unit Tests area waste of time Maybe invest in writing better Unit Tests? 12
  • 13.
    Unit Tests areeasy! ● Easy to write ○ Easy to write poorly ● What do we do wrong? ○ Strongly couple our tests to our code ○ Thinking about yourself ○ Not getting ‘Bang for the bucks’ 13
  • 14.
    TDD vs UnitTests Not the same thing! 14
  • 15.
    TDD vs UnitTests A test you wrote to do TDD may not be valuable for you in the long term Just because a test was useful to help you create a feature doesn’t mean it needs to stay 15
  • 16.
    TDD vs UnitTests ● Maybe the test doesn’t add value ○ What is the ROI on having this test? ○ How many phone calls does it prevent? ● Maybe deleting it isn’t right but… ○ How about making it more useful? 16
  • 17.
    TDD vs UnitTests ● If this test was failing right now what clues would you want it to give you to help you solve the issue faster ○ Work together to find out what that is and then change your test accordingly ○ Test goes from helping you deliver to helping you maintain value 17
  • 18.
    TDD ● TDD isa technique to help you write code and defining a nice way to use it ○ Not necessarily a good way to ensure that feature is well tested if it even needs lots of tests at all ○ How much time will be spent maintaining the tests? 18
  • 19.
    Approachability ● Let’s imaginea 6 month old failing test ○ What clues does it give me? ○ Does it explain the domain? ○ How much test code do you have to wade through to find out what it does? ○ Is it DRY? ■ This doesn’t mean the least characters possible… 19
  • 20.
    Let’s talk aboutDRY ● Often see a broken test that is unrelated ○ Wouldn’t it be great if you could quickly see what was going on... ○ Then you wouldn’t be so annoyed! Repeating yourself to help others understand what is going on is probably a good idea 20
  • 21.
    Let’s talk aboutDRY Apply DRY on a test suite level Apply DRY on a single test 21
  • 22.
    Let’s talk aboutDRY ● In a group of tests you can repeat things ○ What happens when 2 out of 5 tests in a test fixture fail? ○ Duplication can lead to more maintainable tests ○ Always ask what is the value of the test? 22
  • 23.
    Data Builders ● Avoidusing ObjectMother pattern ○ Breaks down when needing different data ○ Personas -> Bob & Jane both have different attributes ● Create data builders - Nat Pryce ○ http://www.natpryce.com/articles/000714.html 23
  • 24.
    Some things toavoid ● Avoid ○ Looping ○ Language Constructs ○ Reflection Stay in domain code as much as possible 24
  • 25.
    Maintainability Tests should bejust as maintainable as the rest of the codebase We don’t need to approach writing tests in quite the same way as production code 25
  • 26.
    Different Thinking Approach testsin a way where readability is more important than performance Milliseconds don’t matter (probably) However, test suites need to be fast! 26
  • 27.
    Too many tests ●Too many tests… not enough tests… ○ Both are suboptimal ● Not enough then too long spent debugging ● Too many then too long to run and maintain ○ Both lead to WASTE 27
  • 28.
    Code Coverage ● Useful! ●Not looking for 100% code coverage ○ End up doing random things like testing getters and setters ○ Don’t have to test third party libraries 28
  • 29.
    What to test? Themost complex parts of the system that add the most value Lots of tests in Allium for example Maybe too many? 29
  • 30.
    Test different things ●What different types of tests? ○ Fast tests - mock things out ○ Database tests - slow but useful? ○ Etc. Want test suite to be fast but depends on needs ● Maybe you need one database test per suite? 30
  • 31.
    Test Categories ● StateVerification ○ Check the state of the system after it has been exercised and compare it to the expected state ■ e.g. Assert.AreEqual(a, b) ● Set up -> Call a function -> Check result 31
  • 32.
    Test Categories ● BehaviourVerification ○ Capture the indirect outputs of the test as they occur and compare them to the expected behaviour ● Mock out -> Verify behaviour happens 32
  • 33.
    Test Categories ● Bothare fine! ○ Consider and think which style suits you or the situation best ● Probably a combination of both 33
  • 34.
    Unit Tests ● SolitaryUnit Test ○ Tests that don’t cross boundaries ○ Test a single class at a time ● e.g. Library -> Book ○ Library tests still pass if book changes 34
  • 35.
    Unit Tests ● SociableUnit Test ○ Tests that cross boundaries ○ Test multiple classes at a time ● e.g. Library -> Book ○ Library tests fail if book changes. 35
  • 36.
    Unit Tests ● Cascadingfailures can occur with sociable tests ○ Solitary tests prevent this happening 36
  • 37.
    COMBO TIME ● Writelots of solitary unit tests ○ As many as you can ● One or two sociable unit tests ○ Makes sure that things work together but don't need to test edge cases with slow sociable tests 37
  • 38.
    Stub vs Mock ●Mock used in Behaviour based tests ○ For Verification ● Stub you don’t verify ○ Return canned responses 38
  • 39.
    Going away ● Writelots of fast solitary tests ○ With a few sociable ones too ● Keep your tests approachable ● Keep your tests maintainable ○ Don’t freak out by breaking some of the production code rules to achieve these 39
  • 40.
    Going away ● Makeexpected literals ○ Don’t call method for expected values ○ Convert objects to literals or write custom assertions (that are also tested) - Think Money object ● Get rid of loops ○ Split into individual tests 40
  • 41.
    Going away ● Don’tuse reflection ○ Being clever in tests isn’t a good idea ○ Avoiding LINQ might be a good idea too ● Use Data Builders ○ Don’t use Object Mother pattern 41
  • 42.
    More controversial ● 1assertion per unit test rule ● Get rid of setup methods ○ Failing tests don’t alert you to go look in the setup ○ Write whole story in the tests 42
  • 43.
    Higher Level Tests Alsouseful Such as Integration tests Unit Tests are just the beginning... 43
  • 44.
  • 45.
    How long shouldyou spend? ● 50/50? ● Write Tests -> Write Simplest Thing -> Refactor Test ○ Spending longer on tests then? ○ Don’t test everything though so probably not more time 45
  • 46.
    How long shouldyou spend? ● Anything between 30 and 50% time - unless your TDDing and then deleting so maybe longer as TDD is part of design phase ● Basically, however long you need to! 46
  • 47.
    Wrap up ● Don’tgive up on tests ● Look for ways to improve ROI in writing tests ○ Keep reading - Blogs, Books, Podcasts 47
  • 48.
    Reading Working Effectively withUnit Tests https://www.goodreads.com/book/show/22605938-working-effectively-with-unit-tests Growing Object-Oriented Software https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests Nat Pryce - Data Builders http://www.natpryce.com/articles/000714.html 48