Montag, 30. April 2012

Extending the Testclass for Unittests

In one of my last articles on Testclasses for symfony2 I explained some of the classes I use for my tests. Since then I found a great article on metatesting and want to update my UnitTest class to show some practical examples.

Using reflections to access private properties

Till now, my UnitTestCase class contained not a single method. I created it for cases I will illustrate now. I created a entity (a simple data object) with a private attribute which is used by Doctrine2 (namely an id) but should not be visible to any class, so it is a private attribute. To test this class, I need to change the value of the id and even retrieve it to see if it changed the correct way.

So, first I create a method for my emtpy UnitTestCase class to get the attribute of a object like this:

protected function getAttribute($object, $name) {
        $reflectionProperty = new \ReflectionProperty(get_class($object), $name);
        return $reflectionProperty->getValue($object);

Now I can access every attribute using reflections. As I placed it in the class all my unit tests extend is it avaiable to all my tests. This is neat if I want to use it somewhere I didn't thought I need it. I also create a method which changes the value of an attribute of an object:

protected function setAttribute($object, $name, $value) {
        $reflectionProperty = new \ReflectionProperty(get_class($object), $name);
        $reflectionProperty->setValue($object, $value);


Alright, now I can get and set all the values even if they are private. If you need to use such "workarounds" often, you are doing it wrong. You want to test your public methods and their outcome. One very reasonable test case is when some property is used with reflection or annotation in the correct usage and you need to dublicate that behaviour in your tests as with a private property in a Doctrine2 entity.

If you find yourself testing every attribute of your class using the above methods, adding more methods to access private methods and the like, you should rethink the way you write your tests. There is nearly no value in testing a helper method which can be tested one level above it by testing the public method it executes. Furthermore, changing the internal behaviour of a class which is not exposed to the public should not break any of your tests. If it does, you will not do the refactoring which is needed because it will be to much work.

Keep going

I also suggest reading "Test-Driven Development by example" by Kent Beck to get you to write better tests. And while you are at amazon, pick up "Refactoring" by Martin Fowler. It really got me going on doing refactorings everytime I work on my code.

Keine Kommentare:

Kommentar veröffentlichen