Slide 1

Slide 1 text

Matt Behrens PyConUK 2016 Building a Python Cake Testing The Layers of Your Application

Slide 2

Slide 2 text

Yelp’s Mission Connecting people with great local businesses.

Slide 3

Slide 3 text

Yelp Stats As of Q2 2016 92M 32 72% 108M

Slide 4

Slide 4 text

Matt Behrens @askedrelic Who Am I?

Slide 5

Slide 5 text

“It’s done, I just have to write the tests” - Every Engineer

Slide 6

Slide 6 text

Tests Are Important!

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

[FAIL CAKE]

Slide 9

Slide 9 text

● The Testing Layer Cake ● Python Recipes ● Lessons and Tips Agenda

Slide 10

Slide 10 text

The Testing Layer Cake Smoke Tests

Slide 11

Slide 11 text

● Fast and consistent validation of one unit of code. ● Build a solid foundation. Unit Tests Don’t: - network calls - database calls - side effects Do: - mocks

Slide 12

Slide 12 text

● AKA fakes, doubles, stubs, the fondant of testing ● A tool for helping test one thing at a time. ● Was the mock called? How many times? What was it called with? Mocks

Slide 13

Slide 13 text

@mock.patch('pybakery.oven') def test_oven_turns_on(mock_oven): mock_oven.turn_on = True the_oven = Oven() assert(the_oven.turn_on() == True)

Slide 14

Slide 14 text

● Test that your units connect together correctly. Test the relationships between your components. ● Are you testing more than one class? ● Mocks okay. ○ Mock data. Mock network or DB calls! Integration Tests

Slide 15

Slide 15 text

● AKA system test, end to end tests ● Test your application end to end, with real data, in a production like environment. ● Try not to use mocks. Acceptance Tests

Slide 16

Slide 16 text

● Sometimes you can’t or won’t test something 100% ○ What tradeoffs do you make to ship? ○ How can you make it easier to test? ● A chance to test in different environments for edge cases ○ Used in Yelp deployment ■ Verify in stage ■ Verify in production with % of live traffic Manual Tests

Slide 17

Slide 17 text

● Simple check that everything is working and testing can continue ○ Is the homepage on fire? ● Generally blackbox and high level ● Related: distributed monitoring is hard ○ See Steve Yegge post about Amazon service architecture breakup Smoke Tests

Slide 18

Slide 18 text

Python Recipes

Slide 19

Slide 19 text

● Pytest ○ Fixtures ○ Parameterized test data ○ Plugins ● Mock ○ Python 3.3+ builtin How To Unit and Integration Test

Slide 20

Slide 20 text

● Test one thing ○ Anti-pattern is to expand your tests to cover multiple situations ● Think about structure of a test ○ Setup ○ Test ○ Validate How To Write Good Unit Tests

Slide 21

Slide 21 text

@pytest.fixture def sprinkles(): return ["°*°*°", '*~*~*~*~', '♥•**•**•♥'] def test_cake(sprinkles): cake = build_cake() # setup cake.bake(sprinkles) # test assert cake.tasty == True # validate

Slide 22

Slide 22 text

● Use as needed ○ Don’t mock too much or too little ○ Anti-pattern is having too many mocks ● Check correct mock call_count ○ Anti-pattern is using mock assert_called_once_with ○ See Yelp Engineer blog post for more info How To Write Good Mocks

Slide 23

Slide 23 text

@pytest.yield_fixture def mock_bake(): with mock.patch( 'pybakery.cake.logic.oven.bake' ) as mock_fn: yield mock_fn def test_cake(mock_bake): ...

Slide 24

Slide 24 text

● Use a mirror structure pybakery/cake/logic/sprinkles.py tests/cake/logic/test_sprinkles.py How To Organize Unit Tests . ├─pybakery/cake/logic/oven.py └────tests/cake/logic/test_oven.py

Slide 25

Slide 25 text

● Docker ○ Tool for running processes/environments in isolation ○ Real MySQL process, real SQL data ● Good ○ Relatively easy to setup ● Not so good ○ Young project, changing rapidly ○ Difficult to understand sometimes How To Acceptance Test

Slide 26

Slide 26 text

Lessons and Tips

Slide 27

Slide 27 text

● How much of your program is executed, when your (unit/integration) tests run ● You probably don’t need 100% coverage! ● Always good to know and improve on Code Coverage

Slide 28

Slide 28 text

● Is a global input! ● Don’t forget to make it a function argument! You will want to override it. ● Freezegun is library to mock time ○ Supports Python 2, 3 Time

Slide 29

Slide 29 text

● Pattern for building a specific types of objects ● Invest in making your testing easier def create(sprinkles=True, **kwargs): options.update(kwargs) Cake(**options) Factories def create(sprinkles=True, **kwargs): default_cake_options = {‘sprinkles’: sprinkles} default_cake_options.update(kwargs) Cake(**default_cake_options)

Slide 30

Slide 30 text

● Super easy to test ○ Just inputs and outputs. Eliminate side effects! ● Think about what layers you are building ● Python Builtins ○ import itertools, functools ○ map(), filter(), reduce(), any(), all() ○ List comprehensions Functional Programming

Slide 31

Slide 31 text

1. Write a test first 2. Watch it fail 3. Write the logic to make it succeed 4. Refactor 5. Repeat ● You know when you are done ● You solve the right problem Test Driven Development

Slide 32

Slide 32 text

Each unit should have limited knowledge about other units. ● Depend on interfaces, not objects. ● Make classes easy to swap out. Law Of Demeter

Slide 33

Slide 33 text

How can you change the structure of your code to make it easier to test? Final Thoughts

Slide 34

Slide 34 text

Questions? @askedrelic [email protected] @YelpEngineering