...
Test
...
Data
...
Builder
...
One
...
of
...
the
...
more
...
time-consuming
...
and
...
tedious
...
chores
...
in
...
writing
...
unit
...
tests
...
that
...
involve
...
mocks,
...
is
...
setting
...
up
...
the
...
test
...
data
...
for
...
mock
...
expectations.
...
For
...
example,
...
let's
...
say
...
we
...
are
...
testing
...
service
...
class
...
code
...
like
...
this:
Code Block |
---|
} List<Student> advisees = advisorDao.getAdvisees(); {code} |
Our
...
unit
...
test
...
would
...
use
...
a
...
mock
...
version
...
of
...
advisorDao,
...
and
...
we
...
would
...
tell
...
the
...
mock
...
framework
...
to
...
expect
...
a
...
call
...
to
...
getAdvisees()
...
and
...
for
...
this
...
method
...
call
...
to
...
return
...
a
...
list
...
of
...
Student
...
objects,
...
like
...
so:
Code Block |
---|
} expect(advisorDao.getAdvisees()).andReturn(studentList); {code} |
We
...
would
...
need
...
to
...
manually
...
create
...
the
...
studentList
...
list,
...
instantiate
...
a
...
number
...
of
...
Student
...
objects,
...
and
...
add
...
them
...
all
...
to
...
the
...
list.
...
Perhaps
...
our
...
test
...
also
...
requires
...
us
...
to
...
peek
...
inside
...
the
...
Student
...
objects
...
and
...
examine
...
the
...
enrollment
...
profile
...
or
...
other
...
embedded
...
objects.
...
We
...
would
...
be
...
required
...
to
...
instantiate
...
all
...
of
...
these
...
objects
...
and
...
set
...
them
...
inside
...
our
...
Student
...
objects.
...
This
...
takes
...
a
...
lot
...
of
...
time
...
and
...
is
...
very
...
tedious.
...
The
...
intent
...
of
...
the
...
test
...
data
...
builder
...
framework
...
is
...
to
...
make
...
"helper"
...
classes
...
available
...
that
...
will
...
do
...
a
...
lot
...
of
...
this
...
data
...
setup
...
for
...
the
...
programmer.
...
These
...
will
...
be
...
simple
...
factory
...
classes,
...
instantiating
...
commonly
...
used
...
objects
...
like
...
Student,
...
and
...
populating
...
them
...
with
...
values
...
that
...
make
...
sense.
...
Design
...
considerations:
...
- Make
...
- the
...
- framework
...
- simple
...
- and
...
- easy
...
- to
...
- use
...
- Keep
...
- the
...
- interfaces
...
- uncluttered
...
- Provide
...
- the
...
- basics
...
- that
...
- should
...
- be
...
- good
...
- enough
...
- for
...
- most
...
- tests,
...
- but
...
- allow
...
- the
...
- flexibility
...
- for
...
- unit
...
- tests
...
- to
...
- tweak
...
- the
...
- data
...
- if
...
- necessary.
...
Here
...
is
...
an
...
example
...
of
...
one
...
of
...
these
...
builder
...
classes
...
-
...
it's
...
called
...
CoreDataFactory
...
and
...
is
...
intended
...
to
...
provide
...
common
...
data
...
used
...
across
...
many
...
apps.
...
The
...
interfaces
...
for
...
creating
...
Student
...
objects
...
is
...
like
...
this:
Code Block |
---|
} public Student buildStudent(); public Student buildStudent(String termCode); {code} |
There
...
are
...
just
...
two
...
variations
...
-
...
the
...
first
...
(no-arg)
...
method
...
will
...
return
...
a
...
Student
...
object
...
with
...
all
...
basic
...
data
...
fields
...
filled
...
in.
...
It
...
will
...
also
...
populate
...
enrollment
...
profile
...
information
...
for
...
the
...
current
...
term
...
(based
...
on
...
a
...
simple
...
current
...
date
...
calculation).
...
The
...
second
...
method,
...
taking
...
term
...
code
...
as
...
an
...
argument
...
builds
...
a
...
similar
...
Student
...
object,
...
but
...
it
...
uses
...
the
...
supplied
...
term
...
code
...
for
...
any
...
term-specific
...
data
...
like
...
enrollment
...
profile.
...
The
...
builder
...
methods
...
will
...
randomly
...
generate
...
values
...
for
...
the
...
student
...
name,
...
mit
...
id,
...
pidm,
...
kerb
...
name,
...
etc,
...
so
...
that
...
each
...
student
...
object
...
returned
...
by
...
the
...
builder
...
methods
...
will
...
be
...
different.
...
So
...
a
...
unit
...
test
...
needing
...
Student
...
objects
...
for
...
test
...
data
...
now
...
only
...
needs
...
to
...
do
...
this
...
for
...
each
...
student
...
object:
Code Block |
---|
} Student student = builder.buildStudent(); {code} |
and no longer needs to do this:
Code Block |
---|
and no longer needs to do this: {code} PersonName personName = new PersonName("David", "Lee", "Roth"); String kerbName = "dlr"; String emailAddress = kerbName + "@mit.edu"; int pidm = 12212871; int mitId = 90002312; Student student = new Student(String.valueOf(pidm), String.valueOf(mitId), kerbName, personName, emailAddress); Calendar now = Calendar.getInstance(); student.setCitizenship(new Citizenship("US", "United States")); student.setEthnicity(new StudentEthnicity()); Calendar birthDate = Calendar.getInstance(); birthDate.set(Calendar.YEAR, birthDate.get(Calendar.YEAR) - 20); // Born 20 years ago student.setBirthDate(birthDate.getTime()); student.setDeceased(false); student.setGender(Gender.FEMALE); student.setStudentHolds(new ArrayList<StudentHold>()); student.setVersion(1l); student.setCreateBy("testuser"); student.setCreateDate(now.getTime()); student.setModifyBy("testuser2"); student.setModifyDate(now.getTime()); // Enrollment profile: Set enrollProfiles = new HashSet(); // ... more code that builds enrollment profile objects... student.setStudentEnrollProfiles(enrollProfiles); {code} h3. Test Builder Package / Module Location I originally thought that the test builder factory classes would go into the csf-test module, as they are intended to be helper classes for unit tests. However, because the builder classes use the domain classes, this setup would cause circular dependencies - for example, |
Test Builder Package / Module Location
I originally thought that the test builder factory classes would go into the csf-test module, as they are intended to be helper classes for unit tests. However, because the builder classes use the domain classes, this setup would cause circular dependencies - for example, csf-common-legacy
...
would
...
depend
...
on
...
csf-test,
...
and
...
csf-test
...
would
...
depend
...
on
...
csf-common-legacy.
...
Because
...
of
...
this,
...
it
...
seems
...
to
...
make
...
sense
...
to
...
place
...
the
...
builder
...
classes
...
close
...
to
...
the
...
domain
...
objects
...
they
...
are
...
building.
...
So
...
the
...
CoreDataFactory
...
could
...
go
...
into
...
csf-common-legacy
...
in
...
a
...
new
...
package
...
in
...
the
...
domain
...
area:
...
edu.mit.common.domain.builders
...
A
...
different
...
way
...
of
...
looking
...
at
...
this
...
is
...
that
...
by
...
creating
...
the
...
helper
...
classes,
...
we
...
are
...
just
...
abstracting
...
out
...
duplicate
...
code
...
from
...
the
...
unit
...
test
...
classes
...
themselves.
...
So
...
perhaps
...
the
...
builders
...
do
...
belong
...
in
...
the
...
test
...
hierarchy.
...
They
...
are
...
not
...
strictly
...
unit
...
tests
...
themselves,
...
but
...
by
...
putting
...
them
...
under
...
test,
...
they
...
would
...
only
...
be
...
used
...
when
...
tests
...
were
...
run
...
and
...
would
...
not
...
be
...
deployed
...
as
...
part
...
of
...
an
...
app.
...
Core
...
Data
...
Factory
...
Javadoc
...
Here's
...
a
...
screenshot
...
showing
...
the
...
Javadoc
...
for
...
the
...
Core
...
Data
...
Factory
...
class.
Does the Core Data Factory Satisfy the Goals?
Here's how I think the factory prototype satisfies the goals:
- Make the framework simple and easy to use
Once you have an instance of CoreDataFactory, getting a stucb Student object is a single method call.
- Keep the interfaces uncluttered
Taking student as an example, there are two build options: one that takes no arguments, one that takes a single termCode argument. We could have created a longer arg list for finer grained customization, but it seems better to keep the interface short and simple. If a unit test needs to tweak the data, it can do that after getting the student object.
- Provide the basics that should be good enough for most tests, but allow the flexibility for unit tests to tweak the data if necessary.