SlideShare uma empresa Scribd logo
1 de 31
Baixar para ler offline
TDD in Python With
Pytest
Eddy Reyes
eddy@tasqr.io
http://www.tasqr.io
Overview
● High-level discussion of TDD
● TDD walk-through with pytest
● Mocking with pytest
Not looking to proselytize TDD in this
presentation
● I’m just presenting the concepts and method.
Further Reading
Uncle Bob Martin
● http://blog.8thlight.com/uncle-bob/archive.html
Kent Beck
● Extreme Programming Explained (book)
Is TDD Dead? video series
● https://www.youtube.com/watch?v=z9quxZsLcfo (part 1)
Code From This Presentation
● https://github.com/ereyes01/apug-pytest-prez
What Is TDD?
● Methodology of Implementing Software
● It is NOT a silver bullet!
● It is NOT the only way to write good
software!
○ But, if followed, will help you write solid software!
Effective TDD
● TDD Method- To change a Program:
○ Write a unit test, watch it fail
○ Change the code to make the test pass
○ Rinse, repeat...
● Unit tests are effective when they are self-contained
○ No external dependencies
● TDD is not for prototyping!
○ Use when you fully understand your design and how
to code your solution
Anatomy of a Test
● Given… precondition
● When… X happens
● Then… Y must be true
Tests == Formal Design Spec
● Make your tests as readable as you would a (formal)
specification document.
Python TDD Tools
● Standard library
○ unittest
○ unittest.mock
■ As of Python 3.3
● Nosetests
● pytest
○ http://www.pytest.org
Testing With Pytest
● No classes needed!
● Fully takes advantage of Python’s dynamism to help
you design beautiful tests.
● Use plain Python assert instead of Xunit jargon
● Fixtures
○ Makes it easy to define your test preconditions
○ Fixtures can be nested arbitrarily, allowing complex
dependency trees
○ Cleanup is handled gracefully
Pytest Fixture Example
from my_flask_app import create_app
@pytest.fixture
def app():
app = create_app("test")
return app
@pytest.fixture
def app_client(app):
client = app.test_client()
return client
# GIVEN: app_client
def test_hello_route(app_client):
# WHEN:
reply = app_client.get(“/hello”)
# THEN:
assert reply.data == “Hello World”
Easy Test Dependencies
● Fixtures allow arbitrarily nested test
dependencies, eliminate DRY in your tests!
○ Compare with unittest... fixtures look like:
class TestSomething(unittest.TestCase):
def setUp():
# fixture code here
def tearDown():
# cleanup fixture here
def testSomething():
# test case code here
Example: TDD and Flask Hello World
● Let’s walk through how we would implement
the Flask Hello World example using TDD.
○ http://flask.pocoo.org
● Requirements:
○ Need a Flask app
○ Must reply the text “hello world” to a GET of the
“/hello” route.
Need to Experiment?
● Not yet sure how to build this?
○ Stop your TDD!
○ Play, read docs learn, experiment…
○ Build a prototype if you like
…
● Do NOT commit that code!
○ TDD is not for learning… it’s for executing on
something you already know how to build.
Step 1: Start With A Test
test_hello.py:
def test_hello():
"""
GIVEN: A flask hello app
WHEN: I GET the hello/ route
THEN: The response should be "hello world"
"""
assert True
Step 2: Define Test Dependencies
test_hello.py
import pytest
import hello_app
@pytest.fixture
def app():
return hello_app.app
@pytest.fixture
def test_client(app):
return app.test_client()
def test_hello(test_client):
"""
GIVEN: A flask hello app
WHEN: I GET the hello/ route
THEN: The response should be "hello world"
"""
assert True
Step 2 Cont’d
Step 3: Add hello_app Module
hello_app.py
import flask
app = flask.Flask(__name__)
Step 4: Add Test For /hello Route
test_hello.py
import pytest
import hello_app
@pytest.fixture
def app():
return hello_app.app
@pytest.fixture
def test_client(app):
return app.test_client()
def test_hello(test_client):
"""
GIVEN: A flask hello app
WHEN: I GET the hello/ route
THEN: The response should be "hello world"
"""
response = test_client.get("/hello")
assert response.data.decode("utf-8") == "hello world"
Step 4 Cont’d
Step 5: Add The /hello Route
hello_app.py
import flask
app = flask.Flask(__name__)
@app.route("/hello")
def hello():
return "hello world"
We’re Done!
Congratulations, you’ve just followed TDD to
create a Flask hello world web application!
Real Life is Never That Simple!
● Of course it’s not
● Applications connect to the network,
● Use databases,
● Do I/O on enormous files,
● etc.
Mocking The Edges Of Your App
● Mocks are a testing technique to stub out the
“edges” of your application
○ “Edges” == external components
● You don’t want to test external components
out of your control
○ Network
○ Database
○ Large Files
Mocking with Pytest’s monkeypatch
● Pytest defines a special fixture called monkeypatch
● Allows arbitrary setattr on anything in your tested
code’s namespace
● Example:
def test_unknown_file(monkeypatch):
monkeypatch.setattr("os.path.islink", lambda x: False)
monkeypatch.setattr("os.path.isdir", lambda x: False)
mylib.check_file("/some/path" )
● Monkeypatched symbols are restored in test cleanup
Mocks as Your Own Fixtures
● monkeypatch can be nested within your own fixtures to
define high-level dependencies
● Helps you write clean test code with mocks that follows
the pattern of Given-When-Then
● Mocks help your application code remain separate from
your testing mechanisms.
Let’s Extend Our Flask Example
● We will add a new route:
○ /hacker_news_encoding
○ This route returns the “Content-Encoding” header
value returned by the Hacker News site
● We can’t directly test Hacker News
○ Site could change
○ Site could be down
○ Unreliable test results
Step 6: Add a Test For The Route
MOCK_ENCODING = “mock-encoding”
def test_encoding_header(test_client, mock_encoding_request ):
"""
GIVEN: A flask hello app
A mock request handler
WHEN: I GET the /hacker_news_encoding route
THEN: The response should be the expected Content-Encoding
"""
response = test_client.get("/hacker_news_encoding")
assert response.data.decode("utf-8") == MOCK_ENCODING
Step 7: Add The Mock Fixture
class MockEncodingResponse:
def __init__(self):
self.headers = {"Content-Encoding": MOCK_ENCODING}
def _mock_get(url):
assert url == "https://news.ycombinator.com"
return MockEncodingResponse()
@pytest.fixture
def mock_encoding_request(monkeypatch):
monkeypatch.setattr("requests.get", _mock_get)
Step 7 Cont’d
Step 8: Add The New Route
hello_app.py
import flask
import requests
app = flask.Flask(__name__)
@app.route("/hello")
def hello():
return "hello world"
@app.route("/hacker_news_encoding")
def hacker_news_encoding():
url = "https://news.ycombinator.com"
resp = requests.get(url)
return response.headers["Content-Encoding"]
Step 8 Cont’d
Want The Code?
Fork me on Github!
https://github.com/ereyes01/apug-pytest-prez

Mais conteúdo relacionado

Mais procurados

pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
Yeongseon Choe
 

Mais procurados (20)

Unit Testing in Python
Unit Testing in PythonUnit Testing in Python
Unit Testing in Python
 
Unit Testing like a Pro - The Circle of Purity
Unit Testing like a Pro - The Circle of PurityUnit Testing like a Pro - The Circle of Purity
Unit Testing like a Pro - The Circle of Purity
 
pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기pytest로 파이썬 코드 테스트하기
pytest로 파이썬 코드 테스트하기
 
Workshop unit test
Workshop   unit testWorkshop   unit test
Workshop unit test
 
Java Unit Testing
Java Unit TestingJava Unit Testing
Java Unit Testing
 
Python-oop
Python-oopPython-oop
Python-oop
 
Unit Test
Unit TestUnit Test
Unit Test
 
Python Workshop
Python WorkshopPython Workshop
Python Workshop
 
Understanding Unit Testing
Understanding Unit TestingUnderstanding Unit Testing
Understanding Unit Testing
 
Modern Python Testing
Modern Python TestingModern Python Testing
Modern Python Testing
 
An introduction to Google test framework
An introduction to Google test frameworkAn introduction to Google test framework
An introduction to Google test framework
 
JUnit- A Unit Testing Framework
JUnit- A Unit Testing FrameworkJUnit- A Unit Testing Framework
JUnit- A Unit Testing Framework
 
05 junit
05 junit05 junit
05 junit
 
TDD and Unit Testing in Golang
TDD and Unit Testing in GolangTDD and Unit Testing in Golang
TDD and Unit Testing in Golang
 
UNIT TESTING
UNIT TESTINGUNIT TESTING
UNIT TESTING
 
An Introduction to Unit Testing
An Introduction to Unit TestingAn Introduction to Unit Testing
An Introduction to Unit Testing
 
구글테스트
구글테스트구글테스트
구글테스트
 
Junit
JunitJunit
Junit
 
The Art of Clean code
The Art of Clean codeThe Art of Clean code
The Art of Clean code
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 

Destaque

Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...
Timo Stollenwerk
 
Python Unit Test
Python Unit TestPython Unit Test
Python Unit Test
David Xie
 
Automated Python Test Frameworks for Hardware Verification and Validation
Automated Python Test Frameworks for Hardware Verification and ValidationAutomated Python Test Frameworks for Hardware Verification and Validation
Automated Python Test Frameworks for Hardware Verification and Validation
Barbara Jones
 

Destaque (20)

TDD in Go with Ginkgo and Gomega
TDD in Go with Ginkgo and GomegaTDD in Go with Ginkgo and Gomega
TDD in Go with Ginkgo and Gomega
 
Mocking in python
Mocking in pythonMocking in python
Mocking in python
 
Mozilla Web QA - Evolution of our Python WebDriver framework
Mozilla Web QA - Evolution of our Python WebDriver frameworkMozilla Web QA - Evolution of our Python WebDriver framework
Mozilla Web QA - Evolution of our Python WebDriver framework
 
All about unit testing using (power) mock
All about unit testing using (power) mockAll about unit testing using (power) mock
All about unit testing using (power) mock
 
AUTOMATED TESTING USING PYTHON (ATE)
AUTOMATED TESTING USING PYTHON (ATE)AUTOMATED TESTING USING PYTHON (ATE)
AUTOMATED TESTING USING PYTHON (ATE)
 
Funcargs & other fun with pytest
Funcargs & other fun with pytestFuncargs & other fun with pytest
Funcargs & other fun with pytest
 
Pytest: escreva menos, teste mais
Pytest: escreva menos, teste maisPytest: escreva menos, teste mais
Pytest: escreva menos, teste mais
 
Учим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTestУчим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTest
 
Python Testing Fundamentals
Python Testing FundamentalsPython Testing Fundamentals
Python Testing Fundamentals
 
Python Ireland Nov 2010 Talk: Unit Testing
Python Ireland Nov 2010 Talk: Unit TestingPython Ireland Nov 2010 Talk: Unit Testing
Python Ireland Nov 2010 Talk: Unit Testing
 
Нескучное тестирование с pytest
Нескучное тестирование с pytestНескучное тестирование с pytest
Нескучное тестирование с pytest
 
Comparative Analysis Of GoLang Testing Frameworks
Comparative Analysis Of GoLang Testing FrameworksComparative Analysis Of GoLang Testing Frameworks
Comparative Analysis Of GoLang Testing Frameworks
 
Writing HTTP Middleware In Go
Writing HTTP Middleware In GoWriting HTTP Middleware In Go
Writing HTTP Middleware In Go
 
Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...Python-nose: A unittest-based testing framework for Python that makes writing...
Python-nose: A unittest-based testing framework for Python that makes writing...
 
Python Unit Test
Python Unit TestPython Unit Test
Python Unit Test
 
Python in Test automation
Python in Test automationPython in Test automation
Python in Test automation
 
Data pipelines from zero to solid
Data pipelines from zero to solidData pipelines from zero to solid
Data pipelines from zero to solid
 
Socket Programming In Python
Socket Programming In PythonSocket Programming In Python
Socket Programming In Python
 
Automated Python Test Frameworks for Hardware Verification and Validation
Automated Python Test Frameworks for Hardware Verification and ValidationAutomated Python Test Frameworks for Hardware Verification and Validation
Automated Python Test Frameworks for Hardware Verification and Validation
 
Automated hardware testing using python
Automated hardware testing using pythonAutomated hardware testing using python
Automated hardware testing using python
 

Semelhante a TDD in Python With Pytest

Semelhante a TDD in Python With Pytest (20)

Test Driven Development en Go con Ginkgo y Gomega
Test Driven Development en Go con Ginkgo y GomegaTest Driven Development en Go con Ginkgo y Gomega
Test Driven Development en Go con Ginkgo y Gomega
 
Working With Legacy Code
Working With Legacy CodeWorking With Legacy Code
Working With Legacy Code
 
Behaviour Driven Development and Thinking About Testing
Behaviour Driven Development and Thinking About TestingBehaviour Driven Development and Thinking About Testing
Behaviour Driven Development and Thinking About Testing
 
Bdd and-testing
Bdd and-testingBdd and-testing
Bdd and-testing
 
May 2021 Spark Testing ... or how to farm reputation on StackOverflow
May 2021 Spark Testing ... or how to farm reputation on StackOverflowMay 2021 Spark Testing ... or how to farm reputation on StackOverflow
May 2021 Spark Testing ... or how to farm reputation on StackOverflow
 
Creating a reasonable project boilerplate
Creating a reasonable project boilerplateCreating a reasonable project boilerplate
Creating a reasonable project boilerplate
 
Unit Testing and TDD 2017
Unit Testing and TDD 2017Unit Testing and TDD 2017
Unit Testing and TDD 2017
 
Pentester++
Pentester++Pentester++
Pentester++
 
Spock pres
Spock presSpock pres
Spock pres
 
Xdebug for Beginners
Xdebug for BeginnersXdebug for Beginners
Xdebug for Beginners
 
Writing Tests with the Unity Test Framework
Writing Tests with the Unity Test FrameworkWriting Tests with the Unity Test Framework
Writing Tests with the Unity Test Framework
 
Hadoop: Big Data Stacks validation w/ iTest How to tame the elephant?
Hadoop:  Big Data Stacks validation w/ iTest  How to tame the elephant?Hadoop:  Big Data Stacks validation w/ iTest  How to tame the elephant?
Hadoop: Big Data Stacks validation w/ iTest How to tame the elephant?
 
Test driven development - Zombie proof your code
Test driven development - Zombie proof your codeTest driven development - Zombie proof your code
Test driven development - Zombie proof your code
 
Write unit test from scratch
Write unit test from scratchWrite unit test from scratch
Write unit test from scratch
 
Getting started with unit and functional testing
Getting started with unit and functional testingGetting started with unit and functional testing
Getting started with unit and functional testing
 
UPC Plone Testing Talk
UPC Plone Testing TalkUPC Plone Testing Talk
UPC Plone Testing Talk
 
Tdd is not about testing (C++ version)
Tdd is not about testing (C++ version)Tdd is not about testing (C++ version)
Tdd is not about testing (C++ version)
 
Software Craftmanship - Cours Polytech
Software Craftmanship - Cours PolytechSoftware Craftmanship - Cours Polytech
Software Craftmanship - Cours Polytech
 
A la découverte des google/test (aka gtest)
A la découverte des google/test (aka gtest)A la découverte des google/test (aka gtest)
A la découverte des google/test (aka gtest)
 
Python and test
Python and testPython and test
Python and test
 

Último

%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 

Último (20)

Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban%in Durban+277-882-255-28 abortion pills for sale in Durban
%in Durban+277-882-255-28 abortion pills for sale in Durban
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 

TDD in Python With Pytest

  • 1. TDD in Python With Pytest Eddy Reyes eddy@tasqr.io http://www.tasqr.io
  • 2. Overview ● High-level discussion of TDD ● TDD walk-through with pytest ● Mocking with pytest Not looking to proselytize TDD in this presentation ● I’m just presenting the concepts and method.
  • 3. Further Reading Uncle Bob Martin ● http://blog.8thlight.com/uncle-bob/archive.html Kent Beck ● Extreme Programming Explained (book) Is TDD Dead? video series ● https://www.youtube.com/watch?v=z9quxZsLcfo (part 1) Code From This Presentation ● https://github.com/ereyes01/apug-pytest-prez
  • 4. What Is TDD? ● Methodology of Implementing Software ● It is NOT a silver bullet! ● It is NOT the only way to write good software! ○ But, if followed, will help you write solid software!
  • 5. Effective TDD ● TDD Method- To change a Program: ○ Write a unit test, watch it fail ○ Change the code to make the test pass ○ Rinse, repeat... ● Unit tests are effective when they are self-contained ○ No external dependencies ● TDD is not for prototyping! ○ Use when you fully understand your design and how to code your solution
  • 6. Anatomy of a Test ● Given… precondition ● When… X happens ● Then… Y must be true Tests == Formal Design Spec ● Make your tests as readable as you would a (formal) specification document.
  • 7. Python TDD Tools ● Standard library ○ unittest ○ unittest.mock ■ As of Python 3.3 ● Nosetests ● pytest ○ http://www.pytest.org
  • 8. Testing With Pytest ● No classes needed! ● Fully takes advantage of Python’s dynamism to help you design beautiful tests. ● Use plain Python assert instead of Xunit jargon ● Fixtures ○ Makes it easy to define your test preconditions ○ Fixtures can be nested arbitrarily, allowing complex dependency trees ○ Cleanup is handled gracefully
  • 9. Pytest Fixture Example from my_flask_app import create_app @pytest.fixture def app(): app = create_app("test") return app @pytest.fixture def app_client(app): client = app.test_client() return client # GIVEN: app_client def test_hello_route(app_client): # WHEN: reply = app_client.get(“/hello”) # THEN: assert reply.data == “Hello World”
  • 10. Easy Test Dependencies ● Fixtures allow arbitrarily nested test dependencies, eliminate DRY in your tests! ○ Compare with unittest... fixtures look like: class TestSomething(unittest.TestCase): def setUp(): # fixture code here def tearDown(): # cleanup fixture here def testSomething(): # test case code here
  • 11. Example: TDD and Flask Hello World ● Let’s walk through how we would implement the Flask Hello World example using TDD. ○ http://flask.pocoo.org ● Requirements: ○ Need a Flask app ○ Must reply the text “hello world” to a GET of the “/hello” route.
  • 12. Need to Experiment? ● Not yet sure how to build this? ○ Stop your TDD! ○ Play, read docs learn, experiment… ○ Build a prototype if you like … ● Do NOT commit that code! ○ TDD is not for learning… it’s for executing on something you already know how to build.
  • 13. Step 1: Start With A Test test_hello.py: def test_hello(): """ GIVEN: A flask hello app WHEN: I GET the hello/ route THEN: The response should be "hello world" """ assert True
  • 14. Step 2: Define Test Dependencies test_hello.py import pytest import hello_app @pytest.fixture def app(): return hello_app.app @pytest.fixture def test_client(app): return app.test_client() def test_hello(test_client): """ GIVEN: A flask hello app WHEN: I GET the hello/ route THEN: The response should be "hello world" """ assert True
  • 16. Step 3: Add hello_app Module hello_app.py import flask app = flask.Flask(__name__)
  • 17. Step 4: Add Test For /hello Route test_hello.py import pytest import hello_app @pytest.fixture def app(): return hello_app.app @pytest.fixture def test_client(app): return app.test_client() def test_hello(test_client): """ GIVEN: A flask hello app WHEN: I GET the hello/ route THEN: The response should be "hello world" """ response = test_client.get("/hello") assert response.data.decode("utf-8") == "hello world"
  • 19. Step 5: Add The /hello Route hello_app.py import flask app = flask.Flask(__name__) @app.route("/hello") def hello(): return "hello world"
  • 20. We’re Done! Congratulations, you’ve just followed TDD to create a Flask hello world web application!
  • 21. Real Life is Never That Simple! ● Of course it’s not ● Applications connect to the network, ● Use databases, ● Do I/O on enormous files, ● etc.
  • 22. Mocking The Edges Of Your App ● Mocks are a testing technique to stub out the “edges” of your application ○ “Edges” == external components ● You don’t want to test external components out of your control ○ Network ○ Database ○ Large Files
  • 23. Mocking with Pytest’s monkeypatch ● Pytest defines a special fixture called monkeypatch ● Allows arbitrary setattr on anything in your tested code’s namespace ● Example: def test_unknown_file(monkeypatch): monkeypatch.setattr("os.path.islink", lambda x: False) monkeypatch.setattr("os.path.isdir", lambda x: False) mylib.check_file("/some/path" ) ● Monkeypatched symbols are restored in test cleanup
  • 24. Mocks as Your Own Fixtures ● monkeypatch can be nested within your own fixtures to define high-level dependencies ● Helps you write clean test code with mocks that follows the pattern of Given-When-Then ● Mocks help your application code remain separate from your testing mechanisms.
  • 25. Let’s Extend Our Flask Example ● We will add a new route: ○ /hacker_news_encoding ○ This route returns the “Content-Encoding” header value returned by the Hacker News site ● We can’t directly test Hacker News ○ Site could change ○ Site could be down ○ Unreliable test results
  • 26. Step 6: Add a Test For The Route MOCK_ENCODING = “mock-encoding” def test_encoding_header(test_client, mock_encoding_request ): """ GIVEN: A flask hello app A mock request handler WHEN: I GET the /hacker_news_encoding route THEN: The response should be the expected Content-Encoding """ response = test_client.get("/hacker_news_encoding") assert response.data.decode("utf-8") == MOCK_ENCODING
  • 27. Step 7: Add The Mock Fixture class MockEncodingResponse: def __init__(self): self.headers = {"Content-Encoding": MOCK_ENCODING} def _mock_get(url): assert url == "https://news.ycombinator.com" return MockEncodingResponse() @pytest.fixture def mock_encoding_request(monkeypatch): monkeypatch.setattr("requests.get", _mock_get)
  • 29. Step 8: Add The New Route hello_app.py import flask import requests app = flask.Flask(__name__) @app.route("/hello") def hello(): return "hello world" @app.route("/hacker_news_encoding") def hacker_news_encoding(): url = "https://news.ycombinator.com" resp = requests.get(url) return response.headers["Content-Encoding"]
  • 31. Want The Code? Fork me on Github! https://github.com/ereyes01/apug-pytest-prez