Phpunit, how to check if the method is "nothing"?

class Testme() { public function testMe ($a) { if ($a == 1) { throw new Exception ('YAY'); } } } 

therefore, it is easy to check if it has thrown an exception

 /** * @expectedException Exception */ public function test() { new Testme(1); } 

but what if he did nothing ?

 public function test() { new Testme(2); ?? ? ? ? ? } 
+14
php phpunit
source share
5 answers

Scenarios

You have two possible scenarios when a function does nothing:

Scenario 1: no return

Your function does nothing, because you do not perform actions on it and do not include the return keyword in it:

 public function doNothing() { // Do nothing. } 

Scenario 2: with an expression of return

Your function does nothing, because you are not doing anything in it, and you include the return keyword in it without expressing any return value:

 public function doNothing() { // Do nothing. return; } 

Other scenarios

I will leave the following scenarios for consideration:

  1. The case when you do not return anything, but perform significant actions that can be checked on other objects. In this case, you must perform unit testing of the resulting states of the changed objects.

  2. In case you are not doing anything but returning something, you should do unit testing of the return value.

Exploring the documentation in the PHP manual

For the first case, the PHP manual documents that the computed function expression will be null . It says: http://php.net/manual/en/functions.returning-values.php in a note:

If the return is omitted, NULL will be returned.

In the second case, the PHP manual documents that the computed function expression will also be null . It says: http://php.net/manual/en/function.return.php in a note:

If the parameter is not specified, then parentheses must be omitted and NULL will be returned. [...]

Conclusion

Therefore, it is clearly documented that a function that "does nothing" is necessarily evaluated as null .

How to test a function that does nothing

Just confirm your expectations:

 $this->assertNull( $sut->doNothing() ); 

Thus, you “execute” your function, execute it, making the code cover complete all the lines, and “expect” that “nothing happened” by checking the null value of its evaluation as an expression, as described in the documentation.

How to check a constructor that does nothing

However, to check the constructor ... well ... common sense: what is the purpose of the constructor? Create an object (instance) of a certain type (class), right?

So ... I prefer to start 100% of my unit tests, verifying that $sut was created. This is the VERY first test I write when I create a new object of this class. This is a test that I am writing before the class exists. In the end, this requires a constructor. Red stripe. Then I create a class. The green stripe.

Suppose I have an Email class that accepts a string and will only be created if a valid email is sent and otherwise throws an exception. this is very similar to your question. A constructor that simply "allows creation" or "rejects it by exploding the system."

I would usually 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 [ [ ' alice@example.com ' ], [ ' bob.with-several+symbols@subdomain.another.subdomain.example.ver ylongTLD' ], ] } public function invalidEmailProvider() : array { return [ [ 'missing_at_symbol' ], [ ' charlie@cannotBeOnlyTld ' ], ] } //-------------------------------------------------// // Sut creators // //-------------------------------------------------// private function getSut( string $email ) : Email { return new Email( $email ); } 

Since I use PHP 7.0 and put types everywhere, both when entering parameters and in return types, if the created object was not Email, the getSut () function will fail first.

But even if I write it, omitting the return type, the test checks the expected: new Email( ' valid@example.com ' ); In itself, it is an expression that must be evaluated as "something" of the Email::class .

How to check a constructor that does something

Odor code. The constructor probably shouldn't do the job. If there is, just save the settings. If the constructor "works", in addition to storing the parameters, consider lazy processing on getters or delegating this work to a factory or so.

How to check a constructor that "does nothing but save parameters"

Same as before +, then get the data.

  1. Verify in your first test that the creation is an instance of something.
  2. Then, in another other test, do something similar to a retrieval method, which returns you what was entered into the constructor, even if the constructor did nothing (save it).

Hope this helps.

+9
source share

It's impossible. Add a return and return the result.

 class Testme() { public function testMe ($a) { if ($a == 1) { throw new Exception ('YAY'); } return true; } } 

and then

 $object = new Testme(); $this->assertTrue($object->testMe(2)); 
+3
source share

Note. The credits for this decision go to this related answer . The context may seem a little different, but the solution / workaround works the same. Testing that no exception is thrown is the same as testing a method without a return value.

According to this stream of problems , there is no built-in solution for testing something like DoesNotThrowException in PHPUnit (for now).

So yes, one solution would be to return some dummy value from your method, e.g.

 public function testMe ($a) { if ($a == 1) { throw new Exception ('YAY'); } return true; } 

and then validate it in your test. But if you don't want to change the code just for the test, you can work around it:

 public function testExceptionIsNotThrown() { try { new Testme(2); } catch(Exception $e) { /* An exception was thrown unexpectedly, so fail the test */ $this->fail(); } /* No exception was thrown, so just make a dummy assertion to pass the test */ $this->assertTrue(true); } 

It may seem hacked and not very intuitive, but if it is stupid, but it works, it is not stupid .

+1
source share

I came across the same problem. To make sure that nothing happened, just call the method in your unit test. If it fails, the test will fail anyway.

If you just call your method without an @expectedException annotation like this

 public function test() { new Testme(1); } 

you will get an error

 There was 1 error: 1) Testme::testMe Exception: YAY 
+1
source share

2018+

Today, the best practice is annotation specifically for these cases:

 /** * @doesNotPerformAssertions */ public function testSomething() { $someService = new SomeObject(); $someService->shallNotFail(); } 
+1
source share

All Articles