Slide 1

Slide 1 text

Because Web API Testing Should Be Easy Honza Javorek

Slide 2

Slide 2 text

Because Web API Testing Should Be Easy Honza Javorek

Slide 3

Slide 3 text

Design APIs for humans and test what you promised Honza Javorek

Slide 4

Slide 4 text

Honza honzajavorek.cz

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Interface of libraries pip install django

Slide 7

Slide 7 text

Interface of systems curl https://api.github.com/repos/django/django curl http://www.cnb.cz/cs/financni_trhy/devizovy_trh/ kurzy_devizoveho_trhu/denni_kurz.txt

Slide 8

Slide 8 text

User interface

Slide 9

Slide 9 text

import urllib2 gh_url = 'https://api.github.com' req = urllib2.Request(gh_url) password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() password_manager.add_password(None, gh_url, 'user', 'pass') auth_manager = urllib2.HTTPBasicAuthHandler(password_manager) opener = urllib2.build_opener(auth_manager) urllib2.install_opener(opener) handler = urllib2.urlopen(req) print handler.getcode() print handler.headers.getheader('content-type') Do you like this interface?

Slide 10

Slide 10 text

Requests: HTTP for Humans

Slide 11

Slide 11 text

>>> r = requests.get('https://api.github.com/user', ... auth=('user', 'pass')) >>> r.status_code 200 >>> r.headers['content-type'] 'application/json; charset=utf8' >>> r.encoding 'utf-8' >>> r.text '{"type":"User"...' >>> r.json() {'disk_usage': 368627, 'private_gists': 484, ...} Do you like this interface?

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

How did Kenneth do it?

Slide 14

Slide 14 text

How do you design the interface?

Slide 15

Slide 15 text

def test_basic_building(): req = requests.Request() req.url = 'http://kennethreitz.org/' req.data = {'life': '42'} pr = req.prepare() assert pr.url == req.url assert pr.body == 'life=42'

Slide 16

Slide 16 text

Writing tests first helps to design the interface TDD

Slide 17

Slide 17 text

test > RED > implement > test > GREEN req = requests.Request() req.url = 'http://kennethreitz.org/' req.data = {'life': '42'} pr = req.prepare() assert pr.url == req.url assert pr.body == 'life=42'

Slide 18

Slide 18 text

Writing down behavior first helps to design the interface BDD

Slide 19

Slide 19 text

Feature: Status code Background: Given you expect HTTP status code "200" Scenario: Different real response status When real status code is "500" Then Gavel will set some error for "status code" And Request or Response is NOT valid Scenario: Response status code match When real status code is "200" Then Gavel will NOT set any errors for "status code" And Request or Response is valid Gherkin / Cucumber

Slide 20

Slide 20 text

Testable documentation!

Slide 21

Slide 21 text

RDD

Slide 22

Slide 22 text

RDD Readme Driven Development http://tom.preston-werner.com/2010/08/23/readme-driven- development.html

Slide 23

Slide 23 text

# Requests The `requests` library allows you to perform HTTP requests from your Python code. ## Example ```python >>> r = requests.get('https://github.com') >>> r.status_code 200 ``` ## License MIT README.md

Slide 24

Slide 24 text

Readme Driven Development • chance to think through the project first • docs are ready - no need to write them retroactively • your team can use the interface before it exists • easy to discuss the interface with everyone

Slide 25

Slide 25 text

Interface in README = Essential interface user expects

Slide 26

Slide 26 text

README must not get out of sync with code

Slide 27

Slide 27 text

How do we ensure implementation matches the design?

Slide 28

Slide 28 text

python -m doctest README.md doctest

Slide 29

Slide 29 text

language: "python" python: - "3.6" script: - "python -m doctest README.md" Continuous Integration

Slide 30

Slide 30 text

What if we could design and test web APIs like this?

Slide 31

Slide 31 text

# Calendar API The API gives you various means to work with date and time. ## GET /now Provides you with current date and time. - Response 200 (application/json) ```json { "day": 29, "month": 2, "year": 2017, "hour": 11, "minute": 45, "second": 38 } ``` API.md

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

dredd API.md http://localhost:8000 Dredd

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

language: "python" python: - "3.6" before_install: - "npm install -g dredd" script: - "dredd API.md http://localhost:8000" Continuous Integration

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

Testing implementation against design allows you designing before implementing

Slide 40

Slide 40 text

Designing before implementing allows you better design

Slide 41

Slide 41 text

Dredd allows you better design

Slide 42

Slide 42 text

Demo

Slide 43

Slide 43 text

Remember • think first, design first, docs first, test first • discuss the the interface design before implementing • use the interface before implementing (mocks, tests) • have your interface design as a single source of truth • test implementation against the design

Slide 44

Slide 44 text

apiary.io