Skip to content

Instantly share code, notes, and snippets.

@justanr
Last active February 17, 2016 14:52
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 justanr/8261384d23d4a7b1d0ad to your computer and use it in GitHub Desktop.
Save justanr/8261384d23d4a7b1d0ad to your computer and use it in GitHub Desktop.
Test Builder
from copy import deepcopy
class Builder(object):
def __init__(self, target, *args, **kwargs):
self._target = target
self._kwargs = kwargs
self._args = list(args)
def having(self, *args, **kwargs):
self._kwargs.update(kwargs)
self._args.extend(args)
return self
def from_(self, **kwargs):
built = {k: v.build() for k, v in kwargs.items()}
return self.having(**built)
def but(self):
args = deepcopy(self._args)
kwargs = deepcopy(self._kwargs)
return self.__class__(self._target, *args, **kwargs)
def build(self):
return self._target(*self._args, **self._kwargs)
def __getattr__(self, attr):
return getattr(self.build(), attr)
class DoesSomething(object):
def __init__(self, user, notifier):
self.user = user
self.notifier = notifier
def tell_user(self, msg):
self.notifier.notify(self.user, msg)
class User(object):
def __init__(self, name, email):
self.name = name
self.email = email
def __repr__(self):
return 'User(name={}, email={})'.format(self.name, self.email)
class Notifier(object):
def notify(self, sender, receiver, msg):
if receiver.name == sender.name:
raise ValueError("Can't send message to self.")
return "{0.name} telling {1.name} about {2}".format(sender, receiver, msg))
def test_build_user_with_defaults():
u = Builder(User, name='jeff', email='jeffmail').build()
assert u.name == 'jeff'
assert u.email == 'jeffmail'
def test_but_overrides_already_provided_values():
u = Builder(User, name='jeff', email='jeffmail').but().having(name='fred').build()
assert u.name == 'fred'
def test_from_adds_to_kwargs():
sink = Builder(dict).from_(user=Builder(User, name='', email='')).build()
assert 'user' in sink
def test_something_complex():
UserBuilder = Builder(User).having('jeff', 'jeffmail')
ds = Builder(DoesSomething).from_(user=UserBuilder).having(notifier=Notifier()).build()
ds.tell_user(UserBuilder.build(), 'hello')
DefaultUser = Builder(User, name='jeff', email='jeffmail')
def test_whatever():
assert DefaultUser.name == 'jeff'
@justanr
Copy link
Author

justanr commented Feb 17, 2016

Given this sort of pattern is far more useful when you have value objects running all around.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment