Skip to content

Instantly share code, notes, and snippets.

@rdammkoehler
Created August 18, 2017 02:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdammkoehler/c0ef0bb3b965ac123e7cd42c82affc92 to your computer and use it in GitHub Desktop.
Save rdammkoehler/c0ef0bb3b965ac123e7cd42c82affc92 to your computer and use it in GitHub Desktop.
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