Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

...

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);

We would need to manually create the studentList list, instantiate a number of Student objects, and add them all to a Listthe 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.

...

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

CoreDataFactory builder = new CoreDataFactory();
Student student = builder.buildStudent();

and no longer needs to do this:

Code Block
        PersonName personName = new PersonName("David", "Lee", "Roth");
        String kerbName = nameGenerator.getName()"dlr";
        String emailAddress = kerbName + "@mit.edu";
        
        Random random = new Random();
        int pidm = 12212871;  // should be int between 100,000 and 199,999
        int mitId = 90002312; // should be int between 900,000,000 and 990,000,000
        
        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);

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.

Image Added

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.