Create a gist now

Instantly share code, notes, and snippets.

@rdammkoehler /tamale.py Secret
Created Aug 18, 2017

What would you like to do?
from unittest import TestCase
from mock import MagicMock, call, patch
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm.attributes import InstrumentedAttribute
from sqlalchemy.orm.properties import ColumnProperty
from sqlalchemy.ext.declarative import as_declarative
@as_declarative()
class Base(object):
def __repr__(self):
props = ["%s=%r" % (prop, getattr(self, prop)) for prop in self.__column_props()]
return "%s(%s)" % (self.__class__.__name__, ", ".join(props))
def __column_props(self):
for attr_name in dir(self.__class__):
attr = getattr(self.__class__, attr_name)
if isinstance(attr, InstrumentedAttribute):
if isinstance(attr.property, ColumnProperty):
yield attr_name
class Foo(Base):
__tablename__ = 'foo'
def __init__(self, **kwargs):
super(Foo, self).__init__(**kwargs)
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(32), nullable=False)
class FooDBWriter:
def write_to_db(self, session, models):
for model in models:
session.insert(Foo(**model))
MODEL_OBJECTS = [
{'name': 'Allen Rickman'},
{'name': 'Bruce Willis'},
{'name': 'Samuel L. Jackson'}
]
class UnworkableTestOfDBWriter(TestCase):
def test_write_to_db_inserts_all_models_as_foos(self):
session = MagicMock(autospec=True)
expected_foos = [Foo(**model) for model in MODEL_OBJECTS]
expected_foo_calls = map(call, expected_foos)
FooDBWriter().write_to_db(session, MODEL_OBJECTS)
session.insert.assert_has_calls(list(expected_foo_calls))
# fails because the expected_foos aren't the same instances
# AssertionError: Calls not found.
# Expected: [call(Foo(id=None, name='Allen Rickman')),
# call(Foo(id=None, name='Bruce Willis')),
# call(Foo(id=None, name='Samuel L. Jackson'))]
# Actual: [call(Foo(id=None, name='Allen Rickman')),
# call(Foo(id=None, name='Bruce Willis')),
# call(Foo(id=None, name='Samuel L. Jackson'))]
class WorkingFalsePositiveTestOfDBWriter(TestCase):
@patch('not_what_you_think.Foo', autospec=True)
def test_write_to_db_inserts_all_models_as_foos(self, foo_):
session = MagicMock(autospec=True)
mock_foos = [MagicMock(spec=Foo, autospec=True) for _ in MODEL_OBJECTS]
foo_.side_effect = mock_foos
expected_foo_calls = map(call, mock_foos)
FooDBWriter().write_to_db(session, MODEL_OBJECTS)
session.insert.assert_has_calls(list(expected_foo_calls))
# Test passes, but the values aren't checked!
class ProperTestOfDBWriter(TestCase):
def test_write_to_db_inserts_all_models_as_foos(self):
class FooMatcher:
def __init__(self, foo):
self.foo = foo
def __eq__(self, other):
return self.foo.id == other.id and \
self.foo.name == other.name
def __repr__(self):
return str(self.foo)
session = MagicMock(autospec=True)
foos = [Foo(**model) for model in MODEL_OBJECTS]
foo_call_matchers = map(call, [FooMatcher(foo) for foo in foos])
FooDBWriter().write_to_db(session, MODEL_OBJECTS)
session.insert.assert_has_calls(foo_call_matchers)
# Test passes, checks every call and matches the arguments too
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment