Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Abstract Classes

People also ask

Can you test an abstract class?

The answer is: always test only concrete classes; don't test abstract classes directly . The reason is that abstract classes are implementation details. From the client perspective, it doesn't matter how Student or Professor implement their GetSignature() methods.

Can you test an abstract class in Java?

You can not test whole abstract class. In this case you have abstract methods, this mean that they should be implemented by class that extend given abstract class.

Can you JUnit test an abstract class?

With JUnit, you can write a test class for any source class in your Java project. Even abstract classes, which, as you know, can't be instantiated, but may have constructors for the benefit of “concrete” subclasses.

How do you spy an abstract class?

Spying abstract class using Mockito.spy() method. The Mockito. spy() method is used to create a spy instance of the abstract class. Step 1: Create an abstract class named Abstract1_class that contains both abstract and non-abstract methods.


Unit testing of abstract classes doesn't necessary mean testing the interface, as abstract classes can have concrete methods, and this concrete methods can be tested.

It is not so uncommon, when writing some library code, to have certain base class that you expect to extend in your application layer. And if you want to make sure that library code is tested, you need means to UT the concrete methods of abstract classes.

Personally, I use PHPUnit, and it has so called stubs and mock objects to help you testing this kind of things.

Straight from PHPUnit manual:

abstract class AbstractClass
{
    public function concreteMethod()
    {
        return $this->abstractMethod();
    }

    public abstract function abstractMethod();
}

class AbstractClassTest extends PHPUnit_Framework_TestCase
{
    public function testConcreteMethod()
    {
        $stub = $this->getMockForAbstractClass('AbstractClass');
        $stub->expects($this->any())
             ->method('abstractMethod')
             ->will($this->returnValue(TRUE));

        $this->assertTrue($stub->concreteMethod());
    }
}

Mock object give you several things:

  • you are not required to have concrete implementation of abstract class, and can get away with stub instead
  • you may call concrete methods and assert that they perform correctly
  • if concrete method relies to unimplemented (abstract) method, you may stub the return value with will() PHPUnit method

It should be noted that as of PHP 7 support for anonymous classes has been added. This gives you an additional avenue for setting up a test for an abstract class, one that doesn't depend on PHPUnit-specific functionality.

class AbstractClassTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var AbstractClass
     */
    private $testedClass;

    public function setUp()
    {
        $this->testedClass = new class extends AbstractClass {

            protected function abstractMethod()
            {
                // Put a barebones implementation here
            }
        };
    }

    // Put your tests here
}

That's a good question. I've been looking for this too.
Luckily, PHPUnit already has getMockForAbstractClass() method for this case, e.g.

protected function setUp()
{
    $stub = $this->getMockForAbstractClass('Some_Abstract_Class');
    $this->_object = $stub;
}

Important:

Note that this requires PHPUnit > 3.5.4. There was a bug in previous versions.

To upgrade to the newest version:

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit

Eran, your method should work, but it goes against the tendency of writing the test before the actual code.

What I would suggest is to write your tests on the desired functionality of a non-abstract subclass of the abstract class in question, then write both the abstract class and the implementing subclass, and finally run the test.

Your tests should obviously test the defined methods of the abstract class, but always via the subclass.


Nelson's answer is wrong.

Abstract classes don't require all of their methods to be abstract.

The implemented methods are the ones we need to test.

What you can do is create a fake stub class on the unit test file, have it extend the abstract class and implement only what's required with no functionality at all, of course, and test that.

Cheers.