Fake It Til You Make It: Unit Testing Patterns With Mocks And Fakes by Brian K. Jones

Presenters: Brian K. Jones

PyCon 2012 presentation page: https://us.pycon.org/2012/schedule/presentation/336/

Slides:

Video: https://www.youtube.com/watch?v=hvPYuqzTPIk&list=PLBC82890EA0228306&index=13&feature=plpp_video

Video running time: 49:33

Your Speaker

(00:14)

What’s covered

(01:17)

  • Definitions
  • Patterns
  • Tools

What’s not covered

(01:56)

  • Intro to the unittest module
  • Sales pitch for doing testing at all

What is a “unit test”?

(02:38)

  • A test that exercises a very small amount of code which is completely isolated from any and all dependencies, external or internal
  • Granular – only testing a small piece of code
  • Isolated
  • Localized – tells you exactly where your bug is

When it is no longer a unit test?

(03:38)

  • When something else in the larger system, besides the code under test, has to work.

What is it then?

(03:48)

  • If multiple components of the same class or system are tested, and the test seeks to determine that these components interact in a predictable way, it’s an integration test.
  • If the entire system is being tested to insure compliance with a spec of some kind, it’s an acceptance test.

What is “coverage”?

(04:15)

  • A loaded term
  • Often generically referred to as “code coverage”.
  • What you really want is “condition coverage”, “case coverage”, “logic coverage”, “decision-point coverage”, etc.

Use coverage.py

(05:15)

http://nedbatchelder.com/code/coverage/

Speaking of nosetests

(07:04)

  • Nose is a great test discovery tool
  • cd to your test directory and run “nosetests”. Rejoice.
  • nosetests --with-coverage (coverage.py is a nose plugin!)
  • Has a super nice HTML report that highlights covered/uncovered lines
  • Integrates well with Jenkins to present html and provide pretty graphs (managers like those):

Why unit tests?

(07:50)

  • They’re fast
  • They’re simple
  • They provide greater localization of problems than other types of tests often can

Unit tests aren’t enough

(10:13)

Unit tests don’t test integration - that the parts of the system all work together

A problem

(10:54)

(Sample Python code from PyRabbit)

A solution

(11:55)

An integration test

(12:05)

(12:26) “Reality distortion field”

Mock is cool. Use it.

(12:40)

  • http://mock.readthedocs.org/en/latest/index.html
  • It patches all the things
  • Often used as a “spy” library (technically)
  • I use it so I don’t have to create my own mocking classes.
  • Action->Assertion > Record->Replay
    • Action->Assertion is closer to how developers tend to think about their code

Mock handles harder stuff

(13:54)

...

Diagram

(15:10)

...

More testable code

(17:00)

Why there is resistance to adopting unit testing

Requires deeper knowledge of code

Requires special techniques

You have to invest time to learn it

A lot of managers, especially with large code bases, will not want to make that investment

However, unit testing will improve the design of your code.

Low-hanging fruit

(17:58)

  • Limit the scope of responsibility
  • Create local wrappers
  • Deduplicate the code

An example

(19:52)

get_path method

(21:20)

(22:15)

Practical patterns Part 1: A datetime abstraction library

(23:27)

Practical patterns Part 2: A REST client module

(28:54)

pyrabbit

  • It’s a cient for RabbitMQ’s REST Management API
  • ~250 lines of executable code
  • ~200 lines of unit test code
  • Uses httplib2 to talk to the server
  • Tests pass with Python 2.6, 2.7, and 3.2
  • Use tox

tox is cool

(30:06)

http://tox.testrun.org/

[tox]
envlist = py26,py27,py32

[testenv]
deps =
    nose
    httplib2
    mock
changedir = tests
commands = nosetests []

[testenv:py26]
deps =
    nose
    httplib2
    mock
    unittest2
changedir = tests
commands = nosetests []

Other tricks

(38:19)

Mocking stdout

(38:27)

outstream = StringIO()

with patch('sys.stdout', new=outstream) as out:
    ...
    actual_out = out.getvalue()

Testing decorated functions

(39:48)

We’ve covered

(41:43)

  • What’s a unit test? Why are they cool? How can I make some?
  • Are unit tests all I need?
  • What’s Mock ? Why is it cool? How can I use it?
  • Use tox! Use nosetests! Use coverage.py!
  • Testing a simple one-module date manipulation library
  • Testing a REST API client library
  • And more!

Questions?

(42:12)

  • Mock is going to be in the Python Standard Library in Python 3.3 as unittest.mock.
  • Question: How to organize integration tests?
  • Question: When do you find doctests useful?
  • Question: Design for testability (e.g.: dependency injection) vs. monkey-patching
    • Dependency injection is something that you need a team to be bought into
  • Comment (from Gary Bernhardt). Decorators make testing harder because they couple things together at compile-time. The solution is dependency injection.