SlideShare ist ein Scribd-Unternehmen logo
1 von 49
Downloaden Sie, um offline zu lesen
Factories, mocks,
spies…
…and other tester’s little helpers
Carles Barrobés
twitter: @technomilk
github: @txels
Testing is a very broad
topic
!
…with its own special lingo
blackbox whitebox
regression unit-test
integration-test
service-test pyramid
icecream-cone factory
assertion spy SuT
…
Let’s start with a question…
!
Why do we write tests?
We write tests to save money
We tell the computer how to do [tedious]
testing for us, faster and cheaper
Writing tests == automation
SuT: System-under-Test*
Your “system” as a black box:
I am system
!
(with a spec,
if you’re lucky)
in
out
in: data, stimuli
out: data, observable behaviour
SuT: System-under-Test
Your “system” as a white/gray box:
I am system
!
(and you can see
what’s inside me)
in
out
…BTW I rely
on a bunch of
external
stuff
SuT: System-under-Test
Your “system” as a white/gray box:
zin
out
…BTW I rely
on a bunch of
external
stuff
Explicit/Injected
dependencies
Implicit/Hardcoded
dependencies
Anatomy of [manual] testing
Take your code up to the point
you want to test
Run the specific feature you are
testing
Verify that it worked
Anatomy of a test case
def test_something_works():
!
prepare
<blank line>
exercise
<blank line>
verify
aka “Arrange, Act, Assert”
Anatomy of a test case
def test_something_works():
!
prepare
<blank line>
exercise
<blank line>
verify
Get your code to a
known state:
Generate test data
Navigate
Isolate and monitor:
Set up mocks
Set up spies
Anatomy of a test case
def test_something_works():
!
prepare
<blank line>
exercise
<blank line>
verify
Call your code:
result = something(data)
Anatomy of a test case
def test_something_works():
!
prepare
<blank line>
exercise
<blank line>
verify
Validate results:
Assertions on results
Check observed
behaviour:
Check reports from
your mocks and spies
Time for another question…
!
Which of those is the
hardest?
Time for the actual talk…
!
Let’s look at tools that
can help us with the hard
bits
Tools for test setup
(I find the preparation phase to be the hardest bit)
[Complex] test data: factories
Test objects with behaviour:
mocks
Instrument internals: spies
Factories
Goal: make it easy to generate
complex test data structures
!
Tool of choice: factory boy*
* I’ve tried others, but I prefer this one
Factories: use cases
Create test data with simple
statements
Let the factory fill [irrelevant] details
Black/white box testing
Explicit dependencies
Factories: simplicity
Example: we need a django model
instance for our test.
It has lots of mandatory fields…
..but in this test we only care about
“title”
Factories: simplicity
Not this:
publisher = Publisher.objects.create(name=‘Old Books’)
book = Book.objects.create(title=‘Tirant Lo Blanc’,
author=‘Joanot Martorell’,
date=1490,
publisher=publisher)
But this:
book = BookFactory(title=‘Tirant Lo Blanc’)
Factory Boy in action
import factory
from books.models import Book, Publisher
!
class PublisherFactory(factory.DjangoModelFactory):
FACTORY_FOR = Publisher
name = ‘Test Publisher’
city = ‘Barcelona’
!
class BookFactory(factory.DjangoModelFactory):
FACTORY_FOR = Book
title = ‘Test Book’
author = ‘Some Random Bloke’
year = 2015
publisher = factory.SubFactory(PublisherFactory)
Maintainability FTW!
When you maintain large tests suites, you
want to maximise reuse [& DRYness]
Defaults and rules for building your objects
live in a central place - easy to adapt
E.g. adding a mandatory field is no longer a pain
Not tied to your test framework
Factory Boy: niceties
Use a sequence for unique values:
name = factory.Sequence(
lambda num: 'Name {}’.format(num)
)
!
Lazy attributes to populate “late”:
slug = factory.LazyAttribute(
lambda obj: slugify(obj.name)
)
Factory Boy: niceties
Fuzzy (randomised) values
title = factory.fuzzy.FuzzyText() # u'phPEZzNqfkXv'
gender = factory.fuzzy.FuzzyChoice(('m', 'f')) # 'm'
age = factory.fuzzy.FuzzyChoice(18, 45) # 27
...
!
Coming soon: Faker support (realistic values)
name = factory.Faker('name') # u'Isla Erdman'
email = factory.Faker('email') # u'vmitchell@stehr.org'
Spies
Goal: check if something
happened inside your code
!
Tool of choice: kgb*
* I don’t know others in Python, used Jasmine (JS)
Spies: use cases
When it’s hard to have externally
observable behaviour
It’s a bit like adding monitoring to your tests
“Blackbox” testing (with some inside
knowledge)
Implicit dependencies
Spies: how to
You know a little what your system
does under the hood
You “spy” on a method that should be
called (the spy is a wrapper that “calls
through”)
Your spy reports on how that method
was called
KGB in action
from unittest import TestCase
from kgb import spy_on
!
def add_three(number):
return number + 3
!
def do_stuff(number):
return add_three(number + 1)
!
class SpyOnTest(TestCase):
def test_spy_on_add_three(self):
with spy_on(add_three) as spy:
result = do_stuff(15)
self.assertEqual(spy.last_call.args, (16,))
self.assertTrue(spy.called_with(16))
KGB extras
You can replace the spied on
method and make it do nothing
or something else
!
with spy_on(SomeClass.add_stuff,
call_fake=add_two):
Mocks
Goal: make it easy to simulate
behaviour of a dependency
!
Tool of choice: mock*
* There are others, I haven’t tried them
Mocks: use cases
Your SuT has explicit callback
dependencies (objects it calls)
You want to feed valid objects and
inspect what your system did to them
Simulate hard to reproduce
conditions (e.g. exceptions)
Mocks vs Factories
Factories generate “real
production objects”
Mocks generate fake objects
(that you can throw anything at)
mock in action
>>> from mock import Mock
>>> user = Mock(username='Fred')
>>> user.username
'Fred'
>>> user.save(force=True)
<Mock name='mock.save()' id='4492633872'>
>>> args, kwargs = user.save.call_args_list[0]
>>> kwargs
{'force': True}
mocking calls
>>> user.save.return_value = True
>>> user.save()
True
>>> user.save.side_effect = Exception('Boom')
>>> user.save()
-------------------------------------------------
Exception Traceback (most recent call last)
...
!
Exception: Boom
mock extras: “patch”
Patch existing code and replace
it with a mock for the duration of
a test
Similar use cases to spies [but
without “call through”]
Mock: “patch” use cases
Your SuT has hardcoded
dependencies but you want to
test it in isolation
You want to accelerate your
tests [by bypassing expensive calls]
patch in action
from mock import patch
!
class MockPatchTest(TestCase):
@patch('test_sample.add_stuff')
def test_do_stuff_calls_add(self, add_stuff):
add_stuff.return_value = ‘whatever'
!
result = do_stuff(123)
!
add_stuff.assert_called_once_with(123)
self.assertEqual(result, 'whatever')
Tools for test validation
Built-in assert_ functions from
your test tool (nose, unittest)
assert statement (if you use py.test
it will give useful reporting)
Matchers (hamcrest)
Matchers
Goal: reusable conditions for
assertions
!
Tool of choice: hamcrest
Matchers: use cases
You want to check complex or
custom conditions in a DRY
way
Matchers can be composed - no
need for “combinatory” assertions
or assertTrue(<complex expression>)
hamcrest highlights
A single assertion: assert_that
Many matchers out of the box (plus you can
write your own)
Useful reporting on mismatches (no more
“False is not True” errors)
Composite matchers:
all_of, any_of, not_
hamcrest in action
def test_any_of(self):
result = random.choice(range(6))
assert_that(result, any_of(1, 2, 3, 4, 5))
!
!
!
AssertionError:
Expected: (<1> or <2> or <3> or <4> or <5>)
but: was <0>
hamcrest in action
def test_complex_matcher(self):
user = UserFactory()
assert_that(
user.email,
all_of(
not_none(),
string_contains_in_order('@', '.'),
not_(contains_string('u'))
)
)
!
AssertionError:
Expected: (not None and a string containing '@', '.' in order and
not a string containing 'u')
but: not a string containing 'u' was 'clangworth@schuster.biz'
Custom matchers
You can write your own
matchers
The syntax is a bit verbose, so I wrote
matchmaker to make it easier
Custom matchers…
from hamcrest.core.base_matcher import BaseMatcher
!
class IsEven(BaseMatcher):
def _matches(self, item):
return item % 2 == 0
!
def describe_to(self, description):
description.append_text('An even number')
!
def is_even():
return IsEven()
…using matchmaker
from matchmaker import matcher
!
@matcher
def is_even(item):
"An even number"
return item % 2 == 0
Custom matchers in use
def test_custom_matcher(self):
user = UserFactory()
assert_that(user.age, is_even())
!
AssertionError:
Expected: An even number
but: was <19>
More custom matchers
@matcher
def ends_like(item, data, length):
"String whose last {1} chars match those for '{0}'"
return item.endswith(data[-length:])
!
def test_custom_matcher(self):
user1, user2 = UserFactory(), UserFactory()
assert_that(
user.email,
ends_like(user2.email, 4),
)
!
AssertionError:
Expected: String whose last 4 chars match those for
'vwalter@yahoo.com'
but: was 'brett.witting@bergnaum.biz'
Thanks!
Any questions?
Carles Barrobés
twitter: @technomilk
github: @txels

Weitere ähnliche Inhalte

Was ist angesagt?

Interaction testing using mock objects
Interaction testing using mock objectsInteraction testing using mock objects
Interaction testing using mock objects
Lim Chanmann
 
Leveraging selenium tests to generate more effective test cases.
Leveraging selenium tests to generate more effective test cases.Leveraging selenium tests to generate more effective test cases.
Leveraging selenium tests to generate more effective test cases.
Cu Nguyen
 
Programming with Java: the Basics
Programming with Java: the BasicsProgramming with Java: the Basics
Programming with Java: the Basics
Jussi Pohjolainen
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passage
Erik Rose
 
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalksSelenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Lohika_Odessa_TechTalks
 

Was ist angesagt? (20)

Grails unit testing
Grails unit testingGrails unit testing
Grails unit testing
 
Exceptions handling in java
Exceptions handling in javaExceptions handling in java
Exceptions handling in java
 
Interaction testing using mock objects
Interaction testing using mock objectsInteraction testing using mock objects
Interaction testing using mock objects
 
Mockito intro
Mockito introMockito intro
Mockito intro
 
Unit testing patterns for concurrent code
Unit testing patterns for concurrent codeUnit testing patterns for concurrent code
Unit testing patterns for concurrent code
 
Testing logging in asp dot net core
Testing logging in asp dot net coreTesting logging in asp dot net core
Testing logging in asp dot net core
 
Error and exception in python
Error and exception in pythonError and exception in python
Error and exception in python
 
Leveraging selenium tests to generate more effective test cases.
Leveraging selenium tests to generate more effective test cases.Leveraging selenium tests to generate more effective test cases.
Leveraging selenium tests to generate more effective test cases.
 
Django Testing
Django TestingDjango Testing
Django Testing
 
Whitebox testing of Spring Boot applications
Whitebox testing of Spring Boot applicationsWhitebox testing of Spring Boot applications
Whitebox testing of Spring Boot applications
 
Testing Spring Boot application in post-JUnit 4 world
Testing Spring Boot application in post-JUnit 4 worldTesting Spring Boot application in post-JUnit 4 world
Testing Spring Boot application in post-JUnit 4 world
 
Programming with Java: the Basics
Programming with Java: the BasicsProgramming with Java: the Basics
Programming with Java: the Basics
 
Django’s nasal passage
Django’s nasal passageDjango’s nasal passage
Django’s nasal passage
 
Unit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnitUnit testing PHP apps with PHPUnit
Unit testing PHP apps with PHPUnit
 
JUnit Pioneer
JUnit PioneerJUnit Pioneer
JUnit Pioneer
 
Introduction to Software Testing
Introduction to Software TestingIntroduction to Software Testing
Introduction to Software Testing
 
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalksSelenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
Selenium with py test by Alexandr Vasyliev for Lohika Odessa Python TechTalks
 
Some testing - Everything you should know about testing to go with @pedro_g_s...
Some testing - Everything you should know about testing to go with @pedro_g_s...Some testing - Everything you should know about testing to go with @pedro_g_s...
Some testing - Everything you should know about testing to go with @pedro_g_s...
 
#codemotion2016: Everything you should know about testing to go with @pedro_g...
#codemotion2016: Everything you should know about testing to go with @pedro_g...#codemotion2016: Everything you should know about testing to go with @pedro_g...
#codemotion2016: Everything you should know about testing to go with @pedro_g...
 
Unit testing with Spock Framework
Unit testing with Spock FrameworkUnit testing with Spock Framework
Unit testing with Spock Framework
 

Andere mochten auch

One-Touch Motorized Table
One-Touch Motorized TableOne-Touch Motorized Table
One-Touch Motorized Table
Justin Clough
 
Intelligence, spies & espionage
Intelligence, spies & espionageIntelligence, spies & espionage
Intelligence, spies & espionage
dgnadt
 
Intoduction to Network Security NS1
Intoduction to Network Security NS1Intoduction to Network Security NS1
Intoduction to Network Security NS1
koolkampus
 
ICCV2009: MAP Inference in Discrete Models: Part 5
ICCV2009: MAP Inference in Discrete Models: Part 5ICCV2009: MAP Inference in Discrete Models: Part 5
ICCV2009: MAP Inference in Discrete Models: Part 5
zukun
 
Scalable Internet Servers and Load Balancing
Scalable Internet Servers and Load BalancingScalable Internet Servers and Load Balancing
Scalable Internet Servers and Load Balancing
Information Technology
 

Andere mochten auch (20)

Pretenders talk at PyconUK 2012
Pretenders talk at PyconUK 2012Pretenders talk at PyconUK 2012
Pretenders talk at PyconUK 2012
 
Traversing the Test Pyramid for Android Development
Traversing the Test Pyramid for Android DevelopmentTraversing the Test Pyramid for Android Development
Traversing the Test Pyramid for Android Development
 
One-Touch Motorized Table
One-Touch Motorized TableOne-Touch Motorized Table
One-Touch Motorized Table
 
Intelligence, spies & espionage
Intelligence, spies & espionageIntelligence, spies & espionage
Intelligence, spies & espionage
 
Functional style programming
Functional style programmingFunctional style programming
Functional style programming
 
Lec 03 set
Lec 03   setLec 03   set
Lec 03 set
 
What is Network Security?
What is Network Security?What is Network Security?
What is Network Security?
 
CITY OF SPIES BY SORAYYA KHAN
CITY OF SPIES BY SORAYYA KHANCITY OF SPIES BY SORAYYA KHAN
CITY OF SPIES BY SORAYYA KHAN
 
Securing Windows web servers
Securing Windows web serversSecuring Windows web servers
Securing Windows web servers
 
Serial Killers Presentation1
Serial Killers Presentation1Serial Killers Presentation1
Serial Killers Presentation1
 
Intoduction to Network Security NS1
Intoduction to Network Security NS1Intoduction to Network Security NS1
Intoduction to Network Security NS1
 
Carrick - Introduction to Physics & Electronics - Spring Review 2012
Carrick - Introduction to Physics & Electronics - Spring Review 2012Carrick - Introduction to Physics & Electronics - Spring Review 2012
Carrick - Introduction to Physics & Electronics - Spring Review 2012
 
ICCV2009: MAP Inference in Discrete Models: Part 5
ICCV2009: MAP Inference in Discrete Models: Part 5ICCV2009: MAP Inference in Discrete Models: Part 5
ICCV2009: MAP Inference in Discrete Models: Part 5
 
Android Application: Introduction
Android Application: IntroductionAndroid Application: Introduction
Android Application: Introduction
 
Noah Z - Spies
Noah Z - SpiesNoah Z - Spies
Noah Z - Spies
 
SAN
SANSAN
SAN
 
Android UI
Android UIAndroid UI
Android UI
 
Scalable Internet Servers and Load Balancing
Scalable Internet Servers and Load BalancingScalable Internet Servers and Load Balancing
Scalable Internet Servers and Load Balancing
 
Functional programming with python
Functional programming with pythonFunctional programming with python
Functional programming with python
 
Trends in spies
Trends in spiesTrends in spies
Trends in spies
 

Ähnlich wie Factories, mocks and spies: a tester's little helpers

Unit testing (workshop)
Unit testing (workshop)Unit testing (workshop)
Unit testing (workshop)
Foyzul Karim
 

Ähnlich wie Factories, mocks and spies: a tester's little helpers (20)

Unit testing - A&BP CC
Unit testing - A&BP CCUnit testing - A&BP CC
Unit testing - A&BP CC
 
Effective testing with pytest
Effective testing with pytestEffective testing with pytest
Effective testing with pytest
 
Property based tests and where to find them - Andrzej Jóźwiak - TomTom Webina...
Property based tests and where to find them - Andrzej Jóźwiak - TomTom Webina...Property based tests and where to find them - Andrzej Jóźwiak - TomTom Webina...
Property based tests and where to find them - Andrzej Jóźwiak - TomTom Webina...
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
 
Testing in Python: doctest and unittest
Testing in Python: doctest and unittestTesting in Python: doctest and unittest
Testing in Python: doctest and unittest
 
Unit testing
Unit testingUnit testing
Unit testing
 
Mockito with a hint of PowerMock
Mockito with a hint of PowerMockMockito with a hint of PowerMock
Mockito with a hint of PowerMock
 
2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests2013 DevFest Vienna - Bad Tests, Good Tests
2013 DevFest Vienna - Bad Tests, Good Tests
 
Testing in Python: doctest and unittest (Updated)
Testing in Python: doctest and unittest (Updated)Testing in Python: doctest and unittest (Updated)
Testing in Python: doctest and unittest (Updated)
 
Unit testing (workshop)
Unit testing (workshop)Unit testing (workshop)
Unit testing (workshop)
 
MT_01_unittest_python.pdf
MT_01_unittest_python.pdfMT_01_unittest_python.pdf
MT_01_unittest_python.pdf
 
Java Unit Testing
Java Unit TestingJava Unit Testing
Java Unit Testing
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
Automated Testing in Django
Automated Testing in DjangoAutomated Testing in Django
Automated Testing in Django
 
SystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features SummarySystemVerilog OOP Ovm Features Summary
SystemVerilog OOP Ovm Features Summary
 
Practical unit testing tips
Practical unit testing tipsPractical unit testing tips
Practical unit testing tips
 
Code igniter unittest-part1
Code igniter unittest-part1Code igniter unittest-part1
Code igniter unittest-part1
 
Testing Django Applications
Testing Django ApplicationsTesting Django Applications
Testing Django Applications
 
Testing in Django
Testing in DjangoTesting in Django
Testing in Django
 
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
 

Kürzlich hochgeladen

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
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
 
+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
 

Kürzlich hochgeladen (20)

%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456LEVEL 5   - SESSION 1 2023 (1).pptx - PDF 123456
LEVEL 5 - SESSION 1 2023 (1).pptx - PDF 123456
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
 
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-...
 
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
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
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
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodology
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verifiedSector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
Sector 18, Noida Call girls :8448380779 Model Escorts | 100% verified
 
%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
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
+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...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 

Factories, mocks and spies: a tester's little helpers

  • 1. Factories, mocks, spies… …and other tester’s little helpers Carles Barrobés twitter: @technomilk github: @txels
  • 2. Testing is a very broad topic ! …with its own special lingo
  • 3. blackbox whitebox regression unit-test integration-test service-test pyramid icecream-cone factory assertion spy SuT …
  • 4. Let’s start with a question… ! Why do we write tests?
  • 5. We write tests to save money We tell the computer how to do [tedious] testing for us, faster and cheaper Writing tests == automation
  • 6. SuT: System-under-Test* Your “system” as a black box: I am system ! (with a spec, if you’re lucky) in out in: data, stimuli out: data, observable behaviour
  • 7. SuT: System-under-Test Your “system” as a white/gray box: I am system ! (and you can see what’s inside me) in out …BTW I rely on a bunch of external stuff
  • 8. SuT: System-under-Test Your “system” as a white/gray box: zin out …BTW I rely on a bunch of external stuff Explicit/Injected dependencies Implicit/Hardcoded dependencies
  • 9. Anatomy of [manual] testing Take your code up to the point you want to test Run the specific feature you are testing Verify that it worked
  • 10. Anatomy of a test case def test_something_works(): ! prepare <blank line> exercise <blank line> verify aka “Arrange, Act, Assert”
  • 11. Anatomy of a test case def test_something_works(): ! prepare <blank line> exercise <blank line> verify Get your code to a known state: Generate test data Navigate Isolate and monitor: Set up mocks Set up spies
  • 12. Anatomy of a test case def test_something_works(): ! prepare <blank line> exercise <blank line> verify Call your code: result = something(data)
  • 13. Anatomy of a test case def test_something_works(): ! prepare <blank line> exercise <blank line> verify Validate results: Assertions on results Check observed behaviour: Check reports from your mocks and spies
  • 14. Time for another question… ! Which of those is the hardest?
  • 15. Time for the actual talk… ! Let’s look at tools that can help us with the hard bits
  • 16. Tools for test setup (I find the preparation phase to be the hardest bit) [Complex] test data: factories Test objects with behaviour: mocks Instrument internals: spies
  • 17. Factories Goal: make it easy to generate complex test data structures ! Tool of choice: factory boy* * I’ve tried others, but I prefer this one
  • 18. Factories: use cases Create test data with simple statements Let the factory fill [irrelevant] details Black/white box testing Explicit dependencies
  • 19. Factories: simplicity Example: we need a django model instance for our test. It has lots of mandatory fields… ..but in this test we only care about “title”
  • 20. Factories: simplicity Not this: publisher = Publisher.objects.create(name=‘Old Books’) book = Book.objects.create(title=‘Tirant Lo Blanc’, author=‘Joanot Martorell’, date=1490, publisher=publisher) But this: book = BookFactory(title=‘Tirant Lo Blanc’)
  • 21. Factory Boy in action import factory from books.models import Book, Publisher ! class PublisherFactory(factory.DjangoModelFactory): FACTORY_FOR = Publisher name = ‘Test Publisher’ city = ‘Barcelona’ ! class BookFactory(factory.DjangoModelFactory): FACTORY_FOR = Book title = ‘Test Book’ author = ‘Some Random Bloke’ year = 2015 publisher = factory.SubFactory(PublisherFactory)
  • 22. Maintainability FTW! When you maintain large tests suites, you want to maximise reuse [& DRYness] Defaults and rules for building your objects live in a central place - easy to adapt E.g. adding a mandatory field is no longer a pain Not tied to your test framework
  • 23. Factory Boy: niceties Use a sequence for unique values: name = factory.Sequence( lambda num: 'Name {}’.format(num) ) ! Lazy attributes to populate “late”: slug = factory.LazyAttribute( lambda obj: slugify(obj.name) )
  • 24. Factory Boy: niceties Fuzzy (randomised) values title = factory.fuzzy.FuzzyText() # u'phPEZzNqfkXv' gender = factory.fuzzy.FuzzyChoice(('m', 'f')) # 'm' age = factory.fuzzy.FuzzyChoice(18, 45) # 27 ... ! Coming soon: Faker support (realistic values) name = factory.Faker('name') # u'Isla Erdman' email = factory.Faker('email') # u'vmitchell@stehr.org'
  • 25. Spies Goal: check if something happened inside your code ! Tool of choice: kgb* * I don’t know others in Python, used Jasmine (JS)
  • 26. Spies: use cases When it’s hard to have externally observable behaviour It’s a bit like adding monitoring to your tests “Blackbox” testing (with some inside knowledge) Implicit dependencies
  • 27. Spies: how to You know a little what your system does under the hood You “spy” on a method that should be called (the spy is a wrapper that “calls through”) Your spy reports on how that method was called
  • 28. KGB in action from unittest import TestCase from kgb import spy_on ! def add_three(number): return number + 3 ! def do_stuff(number): return add_three(number + 1) ! class SpyOnTest(TestCase): def test_spy_on_add_three(self): with spy_on(add_three) as spy: result = do_stuff(15) self.assertEqual(spy.last_call.args, (16,)) self.assertTrue(spy.called_with(16))
  • 29. KGB extras You can replace the spied on method and make it do nothing or something else ! with spy_on(SomeClass.add_stuff, call_fake=add_two):
  • 30. Mocks Goal: make it easy to simulate behaviour of a dependency ! Tool of choice: mock* * There are others, I haven’t tried them
  • 31. Mocks: use cases Your SuT has explicit callback dependencies (objects it calls) You want to feed valid objects and inspect what your system did to them Simulate hard to reproduce conditions (e.g. exceptions)
  • 32. Mocks vs Factories Factories generate “real production objects” Mocks generate fake objects (that you can throw anything at)
  • 33. mock in action >>> from mock import Mock >>> user = Mock(username='Fred') >>> user.username 'Fred' >>> user.save(force=True) <Mock name='mock.save()' id='4492633872'> >>> args, kwargs = user.save.call_args_list[0] >>> kwargs {'force': True}
  • 34. mocking calls >>> user.save.return_value = True >>> user.save() True >>> user.save.side_effect = Exception('Boom') >>> user.save() ------------------------------------------------- Exception Traceback (most recent call last) ... ! Exception: Boom
  • 35. mock extras: “patch” Patch existing code and replace it with a mock for the duration of a test Similar use cases to spies [but without “call through”]
  • 36. Mock: “patch” use cases Your SuT has hardcoded dependencies but you want to test it in isolation You want to accelerate your tests [by bypassing expensive calls]
  • 37. patch in action from mock import patch ! class MockPatchTest(TestCase): @patch('test_sample.add_stuff') def test_do_stuff_calls_add(self, add_stuff): add_stuff.return_value = ‘whatever' ! result = do_stuff(123) ! add_stuff.assert_called_once_with(123) self.assertEqual(result, 'whatever')
  • 38. Tools for test validation Built-in assert_ functions from your test tool (nose, unittest) assert statement (if you use py.test it will give useful reporting) Matchers (hamcrest)
  • 39. Matchers Goal: reusable conditions for assertions ! Tool of choice: hamcrest
  • 40. Matchers: use cases You want to check complex or custom conditions in a DRY way Matchers can be composed - no need for “combinatory” assertions or assertTrue(<complex expression>)
  • 41. hamcrest highlights A single assertion: assert_that Many matchers out of the box (plus you can write your own) Useful reporting on mismatches (no more “False is not True” errors) Composite matchers: all_of, any_of, not_
  • 42. hamcrest in action def test_any_of(self): result = random.choice(range(6)) assert_that(result, any_of(1, 2, 3, 4, 5)) ! ! ! AssertionError: Expected: (<1> or <2> or <3> or <4> or <5>) but: was <0>
  • 43. hamcrest in action def test_complex_matcher(self): user = UserFactory() assert_that( user.email, all_of( not_none(), string_contains_in_order('@', '.'), not_(contains_string('u')) ) ) ! AssertionError: Expected: (not None and a string containing '@', '.' in order and not a string containing 'u') but: not a string containing 'u' was 'clangworth@schuster.biz'
  • 44. Custom matchers You can write your own matchers The syntax is a bit verbose, so I wrote matchmaker to make it easier
  • 45. Custom matchers… from hamcrest.core.base_matcher import BaseMatcher ! class IsEven(BaseMatcher): def _matches(self, item): return item % 2 == 0 ! def describe_to(self, description): description.append_text('An even number') ! def is_even(): return IsEven()
  • 46. …using matchmaker from matchmaker import matcher ! @matcher def is_even(item): "An even number" return item % 2 == 0
  • 47. Custom matchers in use def test_custom_matcher(self): user = UserFactory() assert_that(user.age, is_even()) ! AssertionError: Expected: An even number but: was <19>
  • 48. More custom matchers @matcher def ends_like(item, data, length): "String whose last {1} chars match those for '{0}'" return item.endswith(data[-length:]) ! def test_custom_matcher(self): user1, user2 = UserFactory(), UserFactory() assert_that( user.email, ends_like(user2.email, 4), ) ! AssertionError: Expected: String whose last 4 chars match those for 'vwalter@yahoo.com' but: was 'brett.witting@bergnaum.biz'