Page 1 of 1

Testing attach() method

Posted: Fri Oct 19, 2007 9:02 am
by Luke
I'm testing a method that basically adds to an internal array of the class. How can I test that I have successfully attach()'d something? Reflection?

Code: Select all

$cal->attach($event);
// test that $cal->_children contains $event

Posted: Fri Oct 19, 2007 10:02 am
by Jenk

Code: Select all

$this->assertTrue(in_array($event, $cal->getChildren(), true));
?

Generally speaking, you don't test private methods/properties. They are not part of the interface, and thus not part of the behaviour - however, if you find yourself either wanting to test, or must test, then sometimes it's an indication that it shouldn't be private, or it should have a public accessor (the latter being my preference).

Posted: Fri Oct 19, 2007 10:19 pm
by McGruff
Definitely agree: don't test private properties. Tests should not mention any implementation details otherwise they will be very brittle when you refactor. (Mocks & interaction tests do of course expose some implementation stuff - the method calls on neighbouring objects - but then that's their whole point).

In general you can either:
(1) make assertions on data returned by public methods of the tested class
(2) make assertions based on third party effects such as mock object expectations, files written, database rows inserted, etc.
(3) don't make any assertions at all if it's really trivial such as...

Code: Select all

function getFoo() {
    return $this->foo;
}
If the calendar has methods like getEvents() or getEventsOn($date) you could check for the event in there. That sounds too easy an answer?

The important thing is to stick to your guns. If you've figured out the simplest, easiest to understand interface for a class don't change it or add bits just to make it easier to test.

When you name a test, try and use the language of the domain as far as you can. This might help to keep you thinking about interfaces and behaviours rather than getting caught up in implementation details. You do start to lose that the deeper you get into the object graph, where the language tends to get more technical, but it's always about interfaces and behaviours.

Posted: Sat Oct 20, 2007 2:45 am
by Maugrim_The_Reaper
Just to reiterate - if it's private then don't test it. I'm sure you already know that private stuff can change all the time, whereas a public interface will generally not.

I'm not so sure about avoiding adding new public methods to make testing easier. In many cases you shouldn't because you just end up with class bloat, code serving no real purpose. However I think you should ask the question anyway: Will it add useful functionality? In most cases we're talking about a simple getter - and in some cases users will like that extra getter when it comes to building on your base class for their applications.

Posted: Sat Oct 20, 2007 5:38 am
by Luke
Thanks you all. This has been immensely helpful. This whole thing makes a lot more sense for me now. I'm not sure what it is about unit testing that has kept me so baffled, but for some reason I've just never been able to grasp the concepts. I will try and keep in mind that I should only be testing the public interface as like you guys said, implementation should be able to be changed without having to change the tests too much if at all. :)

Posted: Sat Oct 20, 2007 4:58 pm
by Chris Corbyn
Probably re-iterating, but you should probably just test it the way you want it to work from the face of it (i.e. if you attach() the event does it become available at the correct date in the calendar?) Testing if it's added to the array is just going to cause you to judder and swear once you start to refactor ;)

Posted: Sun Oct 21, 2007 8:52 am
by McGruff
Maugrim_The_Reaper wrote:I'm not so sure about avoiding adding new public methods to make testing easier. In many cases you shouldn't because you just end up with class bloat, code serving no real purpose. However I think you should ask the question anyway: Will it add useful functionality? In most cases we're talking about a simple getter - and in some cases users will like that extra getter when it comes to building on your base class for their applications.
Sometimes code which is hard to test is a smell indicating bad design and changing a class to make it easier to test can lead to a better one. That's probably more to do with shuffling responsibilities around rather than changing the interface. Probably.

I can't quite define this without contradicting myself. As a rule I'd say that yes you definitely want to put the simplest-interface-you-can-think-of first. That's the fixed point which implementations orbit around. You don't want to compromise that if you can avoid it. Code can almost always be thrashed into shape.

At the same time test-first is a process of learning about the domain and testing problems might suggest improvements to the design. I suspect that's not what's happening here but I could be wrong.