Testing and Coding a ValueObject

A simple ValueObject (which is not an Entity, but holds non-persistent data only) has to be immutable to use it properly. It’s the basic idea behind a ValueObject that it’s data stays the same for all of it’s lifetime.

Question #1: What is “immutable” and what is it good for?

“Immutable” simply guaranties, that you will always read the same values from the same ValueObject. The content of the object will never change while your business logic is running. Whenever you need to change some values, you need to create a new ValueObject storing this changed data. Simply: same object === same data. This makes coding very easy and avoids critical and hard-to-find side effects. Reading this in the other way also means: You don’t need to create two different ValueObjects for the same data. Whenever the data is the same, simply use the same ValueObject. [Annotation: This makes garbage collection easy in the background as well.]

Think of this situation: You generate a ValueObject and you send it to a function to do *something*. You don’t know (or you don’t want to care about) the actual implementation of this function. If you want to use this ValueObject later on in your code, you have to trust this function that it doesn’t change your ValueObject. “Trust” is not a good concept in software development, “ensure” is much better. Thus: Make the ValueObject immutable in order to guarantee that it cannot be changed by any unknown / undefined / changing functionality.

Question #2: What’s about setter-Methods?

If you want to make the ValueObject actually immutable, you won’t use any setter-methods at all, because they are supposed to change the content of the ValueObject. Thus you have to send every data to the object’s constructor using a constructor parameter list. Of course you can still use setters, but then you have to ensure (“trust”?!) that some coding guidelines are used that prevent the object from being changed unintentionally. You need to decide on your own, which approach to use. I decided for my source code to use the constructor method. You can use this together with extbase’s ObjectManager as well, because the ObjectManager’s “get” method will route every additional parameter to the called constructor, even if the actual “get”-definition declares the class name parameter only.

Question #3: How do I achieve immutability for objects inside the ValueObject?

It’s very easy to achieve immutability for primitive data types: Just don’t define (or call) setters. Done. It’s more difficult for objects (like a DateTime object for instance) stored inside a ValueObject to stay immutable. Have a look:

class MyValueObject extends Tx_Extbase_DomainObject_AbstractValueObject {
    /**
     * @var DateTime
     */
    protected $dateTime;

    /**
     * @param DateTime
     */
    public function __construct($dateTime) {
        $this->dateTime = $dateTime;
    }

    public function getDateTime() {
        return $this->dateTime;
    }
}

Here you find the property $dateTime storing a DateTime object inside the ValueObject. Usually you would write a very simple getter method like the one above. Let’s have a look at it again:

public function getDateTime() {
    return $this->dateTime;
}

If you retrieve the $dateTime property in this way, you can change it’s value from the outside of the ValueObject without using any setter method:

$myValueObject = $this->objectManager->get(MyValueObject, new DateTime('2014-9-1 11:12:13'));

$localDateTime = $myValueObject->getDateTime();
$localDateTime->modify('+1 day');

// $localDateTime AND $myValueObject->dateTime changed to '2014-9-2 11:12:13'

This will change the $localDateTime value and add one day to the DateTime timestamp, but because $localDateTime is a simple reference to myValueObject’s $dateTime property, it will change the data of the $dateTime property (i.e. the content of the ValueObject) as well. This will lead to side effects, if you rely on your ValueObject to be immutable. Whenever you call getDateTime() later on, you will retrieve a DateTime object with an offset of 1 day to the original (expected) one. A hard-to-find-and-don’t-let-you-sleep-at-night bug. 🙁

Test first

Before we proceed with the solution, we will write a unit test first, because we want to follow the Test First Approach and we want to make sure that we do exactly the right things to achieve our test goals. The test runs like this:

  1. Setup a ValueObject with $dateTime set to a certain date/time.
  2. Get $dateTime from the ValueObject.
  3. Change (i.e. “->modify”) the retrieved DateTime object outside the ValueObject.
  4. Get $dateTime again from the ValueObject and compare it to the modified DateTime object.
  5. Goal: a) they must differ or b) getDateTime() must return the same (immuted) DateTime in the second call.

I’ll go for goal 5b).

Code:

$myValueObject = $this->objectManager->get(MyValueObject, new DateTime('2014-9-1 11:12:13'));
$localDateTime = $myValueObject->getDateTime();

// modifies the retrieved object, but MUST NOT modify the content ($dateTime property) of the ValueObject
$localDateTime->modify('+1 day'); 

$this->assertEquals(new DateTime('2014-9-1 11:12:13'), $myValueObject->getDateTime());

Using the simple getter from above, this test will fail, because “->modify” will change the $dateTime property of the ValueObject as well.

Please note: I used a completely new DateTime object in the assertion at the end of the test. I did this on purpose just to ensure, that I don’t compare an accidentally muted object to an accidental copy of the muted object. It makes the code easier to read and understand and it makes the test safer against any side effects, even if you have to generate a potentially unnecessarily additional object. (Developers don’t want to waste memory by generated unnecessary additional objects, but in this case it is worth the effort.)

Coding the ValueObject (part 1, getter):

Changing the getDateTime() method to secure it’s $dateTime property from being modified from the outside is very simple. Just clone the object before returning it:

public function getDateTime() {
    return clone $this->dateTime;
}

Now you can modify the DateTime object outside the ValueObject without any influence to the $dateTime property.

Challange #2:

Now we’ve created a unit test to prove that the getter method returns an independent object in order to make the inner property immutable. But that’s only half way to the goal. Think of this initialisation:

class MyValueObject {
    //...
    public function __constructor($dateTime) {
        $this->dateTime = $dateTime;
    }
}

$localDateTime = new DateTime('2014-5-13 7:12:17');
$myValueObject = $this->objectManager->get(MyValueObject, $localDateTime);
// more code...
$localDateTime->modify('+1 day');
// even more code...

Which date will be stored in the $dateTime property of the ValueObject at the end of this code? It will be “2014-5-14 7:12:17″. Why? The DateTime object $localDateTime was sent to the ValueObject’s constructor. The constructor stores the reference to this object inside the ValueObject. Whenever the original object is changed (“$localDateTime->modify…”) the reference will point to this changed object. Thus the content of the ValueObject will be changed as well. And finally this means: The ValueObject is not immutable (and that is independent of the strategy to use a setter or a constrctor argument, see above…).

Coding the ValueObject (part 2, setter/constructor):

To avoid this (and the resulting side effects) do what? Of course: Do the test first! Create a ValueObject sending an object to the constructor, change the object and check, if the getter still returns the original values.

        $localDateTime = new DateTime('2014-4-3 1:2:3');
        $myValueObject = $this->objectManager->get(MyValueObject, $localDateTime);
        $localDateTime->modify('+1 day');
        $this->assertEquals(new DateTime('2014-4-3 1:2:3'), $myValueObject->getDateTime());

This will fail for the upper implementation of the ValueObject. Thus we need to make the content of the ValueObject immutable by cloning it inside the constructor as well. Let’s have a look:

class MyValueObject {
    //...
    public function __constructor($dateTime) {
        $this->dateTime = clone $dateTime;
    }
}

Now $this->dateTime is completely independent of all things that happen outside the MyValueObject and the test will end successfully. Let’s sum this up into one test an one ValueObject:

class MyValueObjectTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
    /**
     * @test
     */
    public function clonesCorrectlyAndIsImmutable() {
        $localDateTime = new DateTime('2014-4-3 1:2:3');
        $myValueObject = $this->objectManager->get(MyValueObject, $localDateTime);

        $myValueObject->getDateTime()->modify('-1 day');
        $this->assertEquals(new DateTime('2014-4-3 1:2:3'), $myValueObject->getDateTime(), 'getDateTime() does not clone correctly');

        $localDateTime->modify('+1 day');
        $this->assertEquals(new DateTime('2014-4-3 1:2:3'), $myValueObject->getDateTime(), 'Constructor does not clone correctly');
 }
}
class MyValueObject extends Tx_Extbase_DomainObject_AbstractValueObject {
    /**
     * @var DateTime
     */
    protected $dateTime;

    /**
     * @param DateTime $dateTime
     * @return void
     */
    public function __construct($dateTime) {
        $this->dateTime = clone $dateTime;
    }

    /**
     * @return DateTime
     */
    public function getDateTime() {
        return clone $this->dateTime;
    }
}

The implementation of the ValueObject hasn’t been finished yet, because it does not accept NULL parameters. Please have a look at the “Making a ValueObject NULL-prove” post for more information.

AutoLoader Effect #2: Foreign Sources

I started experimenting with Selenium testcases. Therefor I wanted to use Extbase’s class “SeleniumBaseTestCase” as a root class for all my test cases. This wasn’t possible, because of AutoLoader Effect #1. The autoloader was not able to find this class, because it wasn’t part of Extbase’s “/Classes” directory and it also wasn’t mentioned in Extbase’s “/ext_autoload.php” file.

Well, thinking of AutoLoader Effect #1‘s solution, I simply added an according line to my own “/ext_autoload.php” file, in order to tell the autoloader where to find “SeleniumBaseTestCase”.


$extensionClassesPath = t3lib_extMgm::extPath('csevents') . 'Classes/';
return array(
    'tx_extbase_tests_seleniumbasetestcase' => t3lib_extMgm::extPath('extbase') . 'Tests/SeleniumBaseTestCase.php',
    'tx_csevents_tests_unit_domain_repository_repositorybasetestcase' => $extensionClassesPath . '../Tests/Unit/Domain/Repository/RepositoryBaseTestCase.php',
);

Effect: None – same error, the class cannot be found by the autoloader.

Reason: The autoloader splits the class name, it is searching for, by “_” and searches for the second part, which holds the extension name (“extbase” or “csevents” in my cases). Afterwards it searches for the “ext_autoload.php” file in the extension’s root directory. Thus, searching for “Tx_Extbase_…” makes the autoloader search for “ext_autoload.php” in the “extbase” directory, “my” ext_autoload is never used while searching for “Tx_Extbase_…”. Even if I define the correct solution, the autoloader will never listen to it. Line #3 has absolutly no effect as long as it is not part of the “extbase” extension. 🙁

Solution: None by myself. The extension itself (extbase in this case) has to define all necessary autoload-entries. In this particular case, I was glad that “SeleniumBaseTestCase” is a 1:1 extension of “tx_phpunit_selenium_testcase”, which can be found easily by the autoloader. Thus I used that one. Not nice, but successfull.


<?php

/**
* Base Selenium testcase for the Extbase extension.
*/
abstract class Tx_Extbase_SeleniumBaseTestCase extends tx_phpunit_selenium_testcase {
}
?>

AutoLoader effect #1: “/Tests” Folder

There are some effects of the Extbase AutoLoader, you shall be aware of when writing unit tests.

Testing the repository, I defined a “RepositoryBaseTestCase” which holds common functionality for all 4 repository tests. Simple. Problem: The autoloader was not able to find this class when I tried to extend it.

class Tx_Csevents_Tests_Unit_Domain_Repository_AppointmentRepositoryTest extends Tx_Csevents_Tests_Unit_Domain_Repository_RepositoryBaseTestCase {
}

The base class “Tx_Csevents_Tests_Unit_Domain_Repository_RepositoryBaseTestCase” is on the same directory, but the autoloader is not able to find it. Whenever I try to run the tests, I get the error message “Fatal error: Class ‘Tx_Csevents_Tests_Unit_Domain_Repository_RepositoryBaseTestCase’ not found in /home/.sdb/var/www/html/dummy-4.5.32/typo3conf/ext/csevents/Tests/Unit/Domain/Repository/AppointmentRepositoryTest.php on line 37” Why is that? Simply, it’s because my unit tests are not stored underneath “/Classes”, but underneath “/Tests” (you see the referred base class on the bottom of the screenshot).

screenshot1The autoloader recongnises classes in the “/Classes” folder only, thus it doesn’t find the “RepositoryBaseTestCase.php” when I refer to it as “Tx_Csevents_Tests_Unit_Domain_Repository_RepositoryBaseTestCase”.

Solution: Help the autoloader and give it a file “/ext_autoload.php”:

screenshot2


<?php

$extensionClassesPath = t3lib_extMgm::extPath('csevents') . 'Classes/';
return array(
    'tx_csevents_tests_unit_domain_repository_repositorybasetestcase' => $extensionClassesPath . '../Tests/Unit/Domain/Repository/RepositoryBaseTestCase.php',
);

?>

Now the autoloader knows where to search for the referred class. Please note that you have to use lowercase letters for the array keys until Typo3 4.5.x including.

Using the “extensionClassesPath” with the trailing “Classes/” directory, which is removed by the “../” in the array again, is a little strange. I just used it, because this annotation is used commonly. It reflects the view of the autoloader, which is using “Classes” as it’s base directory to start searching. You may change this, if you feel better then. 😉

You could have done a simple “require_once” instead of all this stuff, but this is forbidden by the coding guidelines. Thus this is the official and nice solution.

The Wow-Effect

Well, if you read my former post, you will find out that I was out of business for weeks. Taking it in another way: I totally forgot what I did in the last minutes before changing systems and going offline.

So now I came back and was a little frightened about my “wake-up from standby” or “recall” of what happened in my project and what’s to be done next. And suddenly I had the “Wow-Effect”: MyLyn and Bugzilla told me exactly, what to do next. MyLyn also highlighted the sourcesfiles for me and SVN showed me, which files I handled last. “Recall” was no problem any more.

And then “Wow-Effect” part 2 striked me with fortunate and happy surprise: I decided to do some finger-exercise in the first place and to change all integer timestamps to DateTime objects. In the past I would have struggled for hours by thinking and thinking again about all side-effects and consequences and if all might work successfully when I use the refacored software the first time. But now I simply klicked the “Test” button, found some defects, handled them and had an “all green” state just after one hour. Perfect!

Once again: Effect #1: You find and handle the defects as early (=as cheap) as possible. effect #2: You are sure that your software is working properly, thus you can erase this task from MyLyn und from your mind and go on with new tasks completly free of any doubts. Life is so easy. 😀

Thus DO YOUR INVESTMENT IN THE BEGINNING, DO YOUR UNIT-TESTS, IT WILL MAKE YOU GLAD JUST IN THE MINUTE YOU (FREQUENTLY) USE IT! And: YOU WILL USE IT FREQUENTLY, BECAUSE IT’S SO SIMPLE AND MAKES YOU HAPPY!

Back in Business again

I went offline for some weeks, ’cause I had to set up a new PC with a new DEV environment. It’s all done now and – just guess – I used a lot of my setup-comments in this blog to find out how to setup my new systems. It worked! 😀 All systems are up and running, let’s go on…

Bugging online again

Fixed the Bugzilla / Mylyn bug by upgrading MyLyn from 3.9.1 to 3.9.2.

In the beginning of this project I faced the issue that Mylyn didn’t sync with Bugzilla any more. I just decided to wait and this was successful. Finally Eclipse delivered a patch which fixed this bug. Now I’m ready to go to use Bugzilla in the way I wanted it to be for all open topics. 🙂

Updated the References accordingly…

Project Configuration Issue solved

I wrote about an issue on my Eclipse Project Setup: I wasn’t able to setup the autocomplete functionality correctly by including extbase, fluid and phpunit as Eclipse projects. Instead I used a workaround by adding the paths to these extensions to my own project’s build path. This isn’t very comfortable, because the folders keep popping up in my project folder while I am concentrating on my own development. Now I finally solved this issue.

What was wrong?

I added 3 empty projects “extbase”, “fluid” and “phpunit” to my Eclipse workspace. This was just fine. To include the actual source code of the extension, I also added the extension directory to the project’s Include Path. Have a look at the screenshot:The three additional Eclipse ProjectsYou see that e.g. the Eclipse project “fluid” hasn’t got any source path, but has got “/var/www/typo3[…]/fluid” as an additional include path. This is fine for the “fluid” project, because it just needs to include these sources. I won’t change them at all, thus I don’t need to have them inside the project listed as actual development folders. FAIL! The problem is that Eclipse does not recognize these folders if it includes this project as a source reference into another (my) project. Thus including this “fluid” project into my “csevents” project didn’t make Eclipse read the fluid’s include path to find sources for autocompletion.

The solution

Grmpf, this is Eclipse basics! I had to change the project’s build path and not the include path. By default the build path is just the Eclipse workspace path. I had to replace it by the actual extension’s path. Have a look at the dialogue:

Changing the Project's Build PathChose the project’s “PHP Build Path” option (I used phpunit in this example) and klick “Link Source…”. In the upcoming dialogue add the path to the actual location of the referred extension and don’t forget to select “Replace existing project source folder entry to solve nesting”. Klick “Ok”. Your Build Path will now look like this:

The new and correct Build PathNow you can remove this path from the Include Path. The Build Path is just enough. If you do it like this, your Eclipse Project will look like this afterwards:

The correct Eclipse Project ReferenceNow it’s an Eclipse Project “phpunit” with a “phpunit” build path inside (which directly links to the phpunit extension folder on my testserver) and an include path which holds the Eclipse Project itself only. This is the correct project setup to have a working project reference with autocompletion.

Feeling good…

Let’s celebrate our achievements. Just run all tests and have a look at the result:

All green, tests doneThat is a very pleasant and comforting feeling. Have a look at the stats: I made a test of the complete Domain Model and of one Repository, checking all getters, setters, the data mapper configuration and the database treatment. That are 25 tests done. And they will be done every time I just start the unit test – and give me the very good feeling that my fundamental data structure and it’s treatment is still working. That lets you concentrate on your complex business middleware job without hesitating about the over all result in the end. That is indeed a very good status to go to bed and sleep well without having thousands of open points rushing though your mind and keeping you awake.

Please note the two grey bars there, telling me that I haven’t finished implementing all tests I already planned to do. Yes, that’s an open point, but I’m aware of it, the system supports me by granting this information to me and I will go on to fill these gaps asap. Nice to have a scout like this…

Demolition Man: Deleting Data

Ok, we read data, we changed data. That’s enough for the constructive way. It’s time to destroy something. The strategy is quite simple: Create data, retrieve it from the database and destroy it, but now, of course, it is very important to check the database, if the data actually was deleted. The code is straight forward:


public function canDeleteAppointmentFromRepository() {
    $testId = 42;
    $uid = $this->setupTestData($testId);
    $appointment = $this->appointmentRepository->findByUid($uid);
    $this->appointmentRepository->remove($appointment);
    unset($appointment);
    $this->persistenceManager->persistAll();
    $appointment = $this->appointmentRepository->findByUid($uid);
    $this->assertNull($appointment, 'Appointment is not NULL after removing it from the repository');
}

Those who are very familiar to software engineering and British SF might find the answer to all questions in line #2. So you don’t need to read on, because this says it all. 🙂

One special thing to remark here is on line #7. In the lines above I just created and removed the Entity Object. Nevertheless the findByUid in line #8 would find the entity object in the database anyway, because it was marked as “deleted” in the repository’s cache, but was not physically removed from the DB. Thus we have to tell the Persistence Manager to update the database. This is done in line #7. What we need for this is an instance of the persistence manager. We get it by a dependency injection:


/**
* @var Tx_Extbase_Persistence_ManagerInterface
*/
protected $persistenceManager;

public function injectPersistenceManager(Tx_Extbase_Persistence_ManagerInterface $persistenceManager) {
    $this->persistenceManager = $persistenceManager;
}

protected function setUp() {
    parent::setUp();
    $this->testingFramework = new Tx_Phpunit_Framework('tx_csevents');
    $this->setupConfiguration();
    $this->appointmentRepository = $this->objectManager->get(Tx_Csevents_Domain_Repository_AppointmentRepository);
    $this->injectPersistenceManager($this->objectManager->get(Tx_Extbase_Persistence_Manager));
}

The first lines are just classic dependency injection: Declare a property to store the reference to the persistence manager and define a function starting with “inject” to inject the actual instance of it.

Now you can argue, if you want to do your injection within the constructor or within the setUp() method. I chose the setUp() method, because there are 3 constructors available, I have to overwrite, but only one setUp() method I can use as a centralized point for setting up all my environment and Testing Fixture. In my opinion it’s the better solution.

Change the Entity and Write it back to the Repository

When the read test was done successfully, doing the change/write test is simple:


public function canWriteChangedAppointmentToRepository() {
    $testId = 1511;
    $uid = $this->setupTestData($testId);
    $appointment = $this->appointmentRepository->findByUid($uid);
    $appointment->setInternalId('Changed internal id #' . $testId);
    $this->appointmentRepository->update($appointment);
    unset($appointment);
    $appointment = $this->appointmentRepository->findByUid($uid);
    $this->assertNotNull($appointment, 'Wasn\'t able to get back the changed data from the DB at all');
    $this->assertEquals('Changed internal id #' . $testId, $appointment->getInternalId(), 'Retrieved not the expected (changed) internal id from the DB.');

    $this->markTestIncomplete('Change more data?!');
}

Please note that in this case I don’t check, if the data is physically changed in the database. I just rely on the repository. If you want to test the database directly, just read on with the next post, which describes how to do this (using data deletion as an example).

Please also note line 12 where I mark the test as being “incomplete”. I was just struggling, if I should change more data of the entity object. This is (clearly on tests only) another way to mark some “to do-s” like I described in the “Refacoring – Avoiding the Frustration” post.

I read somewhere else in a testing blog that they use assertSame over assertEquals, because this checks the type to be the same as well. I’ll follow this recommendation and change my tests later on in this way.