Question

class MyClass {

    private $numeric;

    public function MyMethod($numeric)
    {

        if (! is_numeric($numeric)) {
            throw new InvalidArgumentException
        }

        $this->numeric = $numeric;

    }

}

1 - It is necessary to test whether the class exists?

The PHPUnit has several methods that run automatically, such as assertPreConditions, setUp, and others. It is necessary within these methods check whether the class exists using the assertTrue and class_exists? Example:

protected function assertPreConditions()
{

    $this->assertTrue(class_exists("MyClass"), "The class does not exists.");

}

2 - It is necessary to check if a method exist? If yes, this test should be a separate test or within each unit test?

Suppose we have a method that accepts only numeric type parameters, so we have two tests, one test with the correct parameter and another with incorrect method expecting an exception, right? The correct way to write this method would be ...

This way:

public function testIfMyMethodExists()
{
    $this->assertTrue(method_exists($MyInstance, "MyMethod"), "The method does not exists.");
}

/**
* @depends testIfMyMethodExists
* @expectedException InvalidArgumentExcepiton
*/
public function testMyMethodWithAValidArgument()
{
    //[...]
}

/**
* @depends testIfMyMethodExists
* @expectedException InvalidArgumentExcepiton
*/
public function testMyMethodWithAnInvalidArgument()
{
    //[...]
}

Or this way?

public function testMyMethodWithAValidArgument()
{
    $this->assertTrue(method_exists($MyInstance, "MyMethod"), "The method does not exists.");
}

/**
* @expectedException InvalidArgumentExcepiton
*/
public function testMyMethodWithAnInvalidArgument()
{
    $this->assertTrue(method_exists($MyInstance, "MyMethod"), "The method does not exists.");
    //[...]
}

And why?

3 - What is the real purpose of the @covers and the @coversNothing?

I was reading a document that Sebastian Bergmann the creator of PHPUnit wrote as good practice we should always write @covers and @coversNothing in the methods and class and add these options in the xml:

mapTestClassNameToCoveredClassName="true"
forceCoversAnnotation="true"

and in the whitelist:

<whitelist addUncoveredFilesFromWhitelist="true">
    <directory suffix=".php"></directory>
</whitelist>

But what is the real need for it?

4 - What is the correct way to test a constructor that calls another method?

It seems everything is fine, but not on tests.

Even if I do tests with valid arguments and invalid arguments expecting an exception on the method "MyMethod", that will not happen if I enter an incorrect value in the constructor (The test fails).

And if I test with valid argument, the code coverage does not result in 100%.

public function __construct($numeric)
{
    $this->MyMethod($numeric);
}
Was it helpful?

Solution

I write tests for methods that should exist, to test that the code does what it is expected of it. I also test the InstanceOf() the class (and inherited class definitions) to ensure the object did create what was suppose to be created. If FOO() extends BAR(), then I test that my object created is an InstanceOf(FOO) and InstanceOf(BAR). If the class gets changed to inherit from something else, or has the extends removed, my test will once again inform the developer to check the code to ensure this change is desired. Potentially some inherited functions are being called on FOO, and without the extends from BAR, this code will break.

I write tests on the various code paths that are there to be executed. Therefore, if I expect that the function should throw an exception when bad data is passed, I write a test for that. I do this to also help document our source code. The tests show the expected behavior. If someone removes the exception (new functionality to accept a different parameter type) then the test should be updated to show that this is allowed. Potentially, the change to the parameters could cause a problem elsewhere. Testing this way ensures that years later, I know that code required this to be a number, and I should definitely re-factor the code carefully if I am changing the parameter types.

Using Test Driven Development (TDD) may cause you to not write the code to throw the exception, as you write a test, then the code to make the test pass. As such, you might not be testing all the parameters and their types or values, but I try to do this as best as I can to validate reasonable data input to try to avoid the Garbage In/Garbage Out (GIGO) problem.

All these tests also give me a good code coverage metric, as the majority of the code base is tested, and the code does step through all the lines in the class files. However, testing to this level, and trying to achieve a high code coverage metric, is really a choice for your team to make if this is desired or not.

OTHER TIPS

I can't see any reason nor advantage of writing this kind of tests. If the class or the method doesn't exist your tests will fail anyway. So you don't have any profit from writing them.

Maybe the one exception from above (point 1) could be a situation where you always build SUT using PHPUnit mock framework (theoretically a situation where your SUT is a mock with mocked other method you don't need in particular test is possible, but I can't imagine real situation which leads to it).

In my opinion if the test covers flow path which is completely included in another test - this means that the test is redundant and unnecessary.

edit:

ad 3. Because you want to know which exactly flow path was invoked by particular unit test. Let's say you have two methods A and B. Method B invokes method A. If you don't have @covers annotation test for method B could generate code coverage for method A, and you can't say if your unit tests for A covers code in 100%.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top