-
-
Save rdammkoehler/c0ef0bb3b965ac123e7cd42c82affc92 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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