Page 1 of 1

I'm still a pretty novice mocker :(

Posted: Thu Feb 05, 2009 4:38 am
by Luke
Even though I've been using TDD for over a year at least, I still am a very poor mocker. I just can't seem to get the hang of mocking. So, I think what would help me is if I provide an example of a real world problem I have run into, and get some help doing mocks for it. So here goes...

I have an abstract class qCal_Value_Multi, and I want to test that it can contain multiple values. I do not want to have to create an actual child class just to test it. I'd like to be able to test its base functionality before getting more specific with child classes. So how would I go about this?

I already have qCal_Value, and it is well-tested. qCal_Value_Multi is an abstract class that extends qCal_Value (another abstract). Here is my (bare-bones) unit test case:

Code: Select all

<?php
/**
 * This is a series of tests that ensure that data is property handled in the qCal_Value family of classes
 */
class UnitTestCase_Value extends UnitTestCase {
 
   
    /**
     * Any "multi-value" values should be capable of containing multiple values, separated by commas
     */
    public function testMultiValuesContainListSeparatedByCommas() {
    
        
    
    }
 
}
It is pretty late, but still... I can't seem to figure out where to go here... I have been cheating and just implementing sub-classes and testing those instead of mocking. Somebody please shine some light on this for me :( Should I create an actual subclass of qCal_Value_Multi named MockqCal_Value_Multi and test that?

Re: I'm still a pretty novice mocker :(

Posted: Thu Feb 05, 2009 5:16 am
by Jenk
I do not want to have to create an actual child class just to test it.
There lies your problem, creating a stub child class for "testing only" is not an invalid way to go. :)

Lets say your class was like this:

Code: Select all

abstract class qCal_Value {
  public function getCommaSeparatedList () {
    return implode($this->getDataArray(), ",");
  }
  abstract function getDataArray();
}
 
class ValueStub extends qCal_Value {
  public function getDataArray() {
    return array("a", "b", "c");
  }
}
Then the test would be:

Code: Select all

 
public function testMultiValuesContainListSeparatedByCommas() {
  $calVal = new ValueStub();
  $this->assertEqual($calVal->getCommaSeparatedList(), "a,b,c");
}
HTH :)

Re: I'm still a pretty novice mocker :(

Posted: Thu Feb 05, 2009 5:19 am
by Chris Corbyn
I'm not sure what you're trying to achieve here. Before I begin, can I just make sure that you're not trying to test an abstract class by using a mock? I mean, the SUT itself is not the abstract class? Don't do this, just test each concrete implementation if this is the case. Mocks are used to stand in for dependencies, not to represent the SUT.

But assuming you're talking about something else, could you maybe post a use-case of the code you're looking to test? :)

EDIT | Or if you really want to test the abstract class use a test-specific subclass as Jenk says. Though this might not be very ideal for more complex abstract classes. The thing is, abstract classes usually arise as the result of refactoring and therefore the tests should probably already have been written for the concrete implementation(s).

Re: I'm still a pretty novice mocker :(

Posted: Thu Feb 05, 2009 6:04 am
by jmut
From what I see the point is that you want to test getCommaSeparatedList so you stub the getDataArray() (which possibly involves db calls, intense call etc) and focus test on really if getCommaSeparatedList is doing correct work

Re: I'm still a pretty novice mocker :(

Posted: Fri Feb 06, 2009 3:13 pm
by josh
Instead of mocking I'd use stubbing. Indeed simpletest calls these mocks but I will refer to them as stubs. Basically I'd just keep doing what you're doing, but create the child class as a stub, by that I mean have empty methods. Wether you hard code return values as string constants or use $mockObj->setReturnValue() is entirely up to you. I use the "stub" framework so that when I do create the implementation for that class I don't have to worry about updating any constants in the tests.

In Jenk's example to stub it I'd just create a stub that implements getCommaSeperatedList() and its implementation would be return 'a, b, c'