2

I know three approaches:

  1. Create fake subclass (looks ugly)
  2. Test one of real subclasses
  3. Use getMockForAbstractClass() (contradicts with mocks' mission; also can't stub not-abstract methods)

What the best way according unit test concept?

edorian
  • 38,542
  • 15
  • 125
  • 143
Darkside
  • 659
  • 8
  • 20
  • 1
    Gordons answer pretty much sums up my point too so I'll just add a coment. I test everything in the base class that doesn't rely on the abstract methods to exists in the abstract class and the rest in the base classes. While one could argue that there is no need to test the base class at all and only test the derived classes (maybe with a base test class ;) ?) it most of the times isn't worth the hassle. So I'd go for 4 "Test all subclasses and the enclosed functions in the baseclass only once" – edorian Mar 23 '11 at 14:52

2 Answers2

4

I would only write tests for concrete classes derived from the abstract class. If you find you are duplicating tests among them, write a superclass and move the duplicated tests there or use getMockForAbstract class for these.

So if you had something like this:

abstract class Employee
{
    protected $name;
    public function getName()
    {
        return $this->name;
    }
    abstract function doWork();
    …
}

class Mechanic extends Employee
{
    public function doWork()
    {
        return // specific to Mechanic
    }
}

class Engineer extends Employee
{
    public function doWork()
    {
        return // specific to Engineer
    }
}

I'd have a test class for Mechanic and Engineer testing their doWork implementation, but not their getName functionality, because that is inherited by the abstract class. For that, I'd write a custom class then or use getMockForAbstractClass, as shown in the example in the PHPUnit Manual:

Gordon
  • 312,688
  • 75
  • 539
  • 559
1

It depends on how functional the abstract class is. When the abstract class is merely there to provide some basic boilerplate with a bunch of template methods, I limit my testing to the concrete subclasses.

When the abstract class is mostly complete I will either create a concrete subclass for the test in the same file as the test case or I will use a mock. Note that getMockForAbstractClass() is just a helper that finds all the abstract methods for you. There's nothing stopping you from declaring all the abstract methods plus some concrete ones with getMock(). For this very reason I override getMock() in our base test case to merge in all the abstract methods before calling the parent.

David Harkness
  • 35,992
  • 10
  • 112
  • 134