class Testme() { public function testMe ($a) { if ($a == 1) { throw new Exception ('YAY'); } } }
so its easy to test if it threw exception
/** * @expectedException Exception */ public function test() { new Testme(1); }
but what if it didn't do anything?
public function test() { new Testme(2); ?? ? ? ? ? }
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.
The assertion methods are declared static and can be invoked from any context using PHPUnit\Framework\Assert::assertTrue() , for instance, or using $this->assertTrue() or self::assertTrue() , for instance, in a class that extends PHPUnit\Framework\TestCase .
You have two possible scenarios for a function to do nothing:
Your function does nothing because you do not perform actions in it and you do not include the return
keyword in it:
public function doNothing() { // Do nothing. }
Your function does nothing because you do not perform actions in it and you do include the return
keyword in it without expressing any return value:
public function doNothing() { // Do nothing. return; }
I will leave out of the cases to treat the following scenarios:
Case in which you do not return anything but you perform significant actions that can be tested on other objects. In this case you must unit-test the resulting states of the modified objects.
Case in which you do nothing but return something, then you should unit-test the return value.
For the first case, the PHP manual documents that the evaluated expression of the function will be null
. It says here: http://php.net/manual/en/functions.returning-values.php in a note:
If the return is omitted the value NULL will be returned.
For the second case, the PHP manual documents that the evaluated expression of the funcion will also be null
. It says here: http://php.net/manual/en/function.return.php in a note:
If no parameter is supplied, then the parentheses must be omitted and NULL will be returned. [...]
It is therefore clearly documented that a function that "does nothing" necessarily evaluates to null
.
Just assert your expectations:
$this->assertNull( $sut->doNothing() );
This way you "exercise" your function, you run over it making the code-coverage complete all the lines, and you "expect" that "nothing happened" by testing the null
value of its evaluation as an expression, as documented.
Nevertheless to test a constructor... well... common sense: What's the purpose of a constructor? Create an object (instance) of a certain type (class), right?
So... I prefer to start the 100% of my unit tests by checking that the $sut
has been created. This is the VERY first test I write when I'm writing the code of a new class. This is the test I write even before the class exists. At the end, this is what the constructor is for. Red bar. Then I create the class. Green bar.
Let's say I have an Email
class that takes a string and will be only created if a valid email is passed and throws exception otherwise. this is very similar to your question. A constructor that just "allows the creation" or "denies it by exploding the system".
I usually would do something like this:
//-------------------------------------------------// // Tests // //-------------------------------------------------// /** @dataProvider validEmailProvider **/ public function testCreationIsOfProperClass( string $email ) { $sut = $this->getSut( $validEmail ); $this->assertInstanceOf( Email::class, $sut ); } /** @dataProvider invalidEmailProvider **/ public function testCreationThrowsExceptionIfEmailIsInvalid( string $invalidEmail ) { $this->expectException( EmailException::class ); $this->getSut( $invalidEmail ); } //-------------------------------------------------// // Data providers // //-------------------------------------------------// public function validEmailProvider() : array { return [ [ '[email protected]' ], [ 'bob.with-several+symbols@subdomain.another.subdomain.example.verylongTLD' ], ] } public function invalidEmailProvider() : array { return [ [ 'missing_at_symbol' ], [ 'charlie@cannotBeOnlyTld' ], ] } //-------------------------------------------------// // Sut creators // //-------------------------------------------------// private function getSut( string $email ) : Email { return new Email( $email ); }
As I use PHP 7.0 and I put types everywhere, both entering the parameters and also in the return types, if the created object was not an Email, the getSut() function would fail first.
But even if I wrote it omitting the return type, the test tests what it is expected to happen: new Email( '[email protected]' );
is itself an expression that shoud evaluate to "something" of class Email::class
.
Code smell. The constructor probably should not do work. If any, just store parameters. If the constructor "does work" other than storing parameters consider lazy-processing on getters, or delegating that work in a factory or so.
Just like before + then get the data.
Hope that this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With