Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit - Writing a test class for an interface, and testing objects using a factory

I am writing a class that will inherit an interface. The client code will be written for that interface, and the class written to support it. The idea is that I will later write other classes for that interface, and objects of those two different classes should be completely interchangeable. Rather than writing a test class for that first class, I want to write one for the interface.

My plan was to write a test class that would take a factory object for the constructor (dependency injection), and use the factory to create new instances of the class under test.

That way, if I wanted to test ClassA, I could pass a ClassAFactory object to the constructor of the test class, and if I wanted to test ClassB, I would pass a ClassBFactory object. Both classes are designed to be interchangeable, and since only public methods are supposed to be tested, this seems ideal.

But what about testing the constructor? Would I be better writing an abstract test class and implmenting constructor tests in classes that inherit the abstract test class (different classes may be instantiated differently)?

If I did use the first idea, I guess I would have a test class for each class being tested, like:

class ClassATest extends [PHPUnit test case]
{
    $myFactory = new ClassAFactory();
    $myTest = new ClassTest($myFactory);

    $myTest->test1();
    $myTest->test2();
    //etc.
}

What's the best way to go about this? I want to have a general test, so that when I write new classes to implement the common interface, I can just put an object of the same tests as used for the others. But, seeing as the different classes would have different constructors, perhaps writing an abstract test class and extending it for each new object would be better? What do you think?

like image 292
Lewis Bassett Avatar asked Dec 23 '11 14:12

Lewis Bassett


People also ask

What is PHPUnit testing?

PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit design for unit testing systems that began with SUnit and became popular with JUnit. Even a small software development project usually takes hours of hard work.

How do I run a PHPUnit test?

How to Run Tests in PHPUnit. You can run all the tests in a directory using the PHPUnit binary installed in your vendor folder. You can also run a single test by providing the path to the test file. You use the --verbose flag to get more information on the test status.

Why do we use PHPUnit?

With unit testing we test each component of the code individually. All components can be tested at least once. A major advantage of this approach is that it becomes easier to detect bugs early on. The small scope means it is easier to track down the cause of bugs when they occur.

What is mock PHPUnit?

Likewise, PHPUnit mock object is a simulated object that performs the behavior of a part of the application that is required in the unit test. The developers control the mock object by defining the pre-computed results on the actions.


2 Answers

I think you need to reconsider your plan. You can't test an interface and there's a good reason why - interfaces just define the API and not functionality, tests test functionality. Let me give you an example that might help. Say you have a "messaging" interface. So you implement an EmailMessager and an SMSMessager. Now you need to test these separately as with the EmailMessager you need to make sure it is doing its stuff, maybe validating the recipient (an email address) and possibly delegating the sending to an email class etc. Obviously an SMS message would be different.

like image 93
liquorvicar Avatar answered Sep 20 '22 12:09

liquorvicar


You can create an abstract test case with all of the test methods using a property that each subclass will set without requiring a factory. It can test the fixed qualities that all implementations must posess.

abstract class IAdderTestCase extends PFTC
{
    function testAdd() {
        self::assertEquals(5, $this->fixture->add(2, 3));
    }
    ...
}

class BasicAdderTest extends IAdderTestCase
{
    function setUp() {
        $this->fixture = new BasicAdder();
    }
}

PHPUnit will call setUp() before each test method. It should call all inherited test methods for each concrete subclass plus any additional ones, e.g. to test the constructors.

like image 21
David Harkness Avatar answered Sep 22 '22 12:09

David Harkness