The "Object Mother"-Pattern
The "Object Mother"-Pattern is known to express in a succinct form what makes an object special.Let's assume we have a domain object Person with the two attributes name and surname.
class Person { String _name, _surname; public Person(String name, String surname) { _name = name; _surname = surname; } }
When we want to assure that a Person object with an empty surname is rejected by a PersonRepository when trying to save it, the simple solution would be the following:
@ExpectedException(ConstraintViolationException.class) @Test public void shouldRejectPersonWithEmptySurname { Person personWithEmptySurname = new Person("Name", ""); personRepository.save(personWithEmptySurname); }
Though this is quite good (when using intent-revealing names), it becomes tedious when you want to test the behaviour in all possible attribute combinations. That's why the "Object Mother"-Pattern is handy. A possible ObjectMother for Person is:
class PersonMother { Person _child = new Person("Name", "Surname"); PersonMother withEmptyName() { _child._name = ""; return this; } PersonMother withEmptySurname() { _child._surname = ""; return this; } Person build() { return _child; } }
Using the PersonMother and a simple factory method we can simplify the test code:
@ExpectedException(ConstraintViolationException.class) @Test public void shouldRejectPersonWithEmptySurname { personRepository.save(aPerson().withEmptySurname().build()); } PersonMother aPerson() { return new PersonMother(); }
And the PersonMother simplifies the combination of attributes, too:
@ExpectedException(ConstraintViolationException.class) @Test public void shouldRejectPersonWithEmptyNameAndSurname { personRepository.save( aPerson() .withEmptyName() .withEmptySurname().build()); }
Using the Object Mother for JMock expectations
After this excursus in the world of patterns, I am approaching my point, finally. Assuming that we want to test the behaviour of a service that depends on a PersonRepository to access persisted persons. In order to test the service in isolation, I mock the PersonRepository. I want to test the behaviour of the service depending on the contents of a returned Person. So we want to return different persons from the mocked repository. With "plain" JMock this results in the following setup code for our mock:PersonRepository mockPersonRepository = context.mock(PersonRepository.class); context.checking(new Expectations() {{ oneOf(mockPersonRepository).get(1); returnValue(aPerson().withoutSurname().build()); }}); [...]
Not bad, actually. Very expressive and readable. But since I am quite a perfectionist, I am bothered by the required call to build(). So, let's see if we can simplify this further.
At first, I extract a generic interface from PersonMother:
interface ObjectMother<T> { T build(); } class PersonMother implements ObjectMother<Person> { [...] }
Afterwards, I create a new method to use in JMock expectations:
static Action returns(ObjectMother<?> objectMother) { return new ReturnValueAction(objectMother.build()); }
With these two ingredients I am able to reduce the mock setup code as I wanted:
PersonRepository mockPersonRepository = context.mock(PersonRepository.class); context.checking(new Expectations() {{ oneOf(mockPersonRepository).get(1); returns(aPerson().withoutSurname()); }}); [...]
Keine Kommentare:
Kommentar veröffentlichen