PHP Test Driven Development Part 4: Enter The Mock
Hey there, welcome to part 4! Today we’ll learn how to mock. Mocking is a process where you create a fake instance of a real class, and test against it. This is so that, you do not have to worry about the real functionality of external dependencies inside a class. This makes unit testing a lot easier and reliable.
Please check out Part3, if you have not read it yet: https://hackernoon.com/php-test-driven-development-part-3-unit-testing-continued-db5d332197ec
Although PHPUnit does have mocking capabilities, it is not as full fledged as that of Mockery’s (http://docs.mockery.io/en/latest/). We’ll be using Mockery for all our mocking needs. Another good thing is that Laravel ships with Mockery by default. We can get started straight away without any installation or configuration :)
First, let’s write some sample code that we’ll use. For the purpose of making it simple, we’ll just make a wrapper class. A wrapper class called “Math” that calls the “Calculate” class. The same “Calculate” class that we made in the previous episode. Let’s make the file with the path “app/Math.php”.
Here, on line 16, we require a Calculate class in the same namespace “App”.
Then we assign it to the same object instance on line 18.
Remember to always opt for dependency injections through the constructor instead of creating them through the “new” keyword inside the methods. This makes testing a lot easier when we make the mocks. Yes, you can still mock the “new” keyword instantiation using Mockery, but it’s almost always a bad idea. Another one is statics, it is best to avoid static calls and instead use their equivalent classes through constructor. If you’re using Laravel framework, you can always check the facade class reference to see what class you can use instead of the static calls. The facade class refrence is at: https://laravel.com/docs/5.7/facades#facade-class-reference
Line 30 is where we call the areaOfSquare method of the dependency ($this->calculate).
So how would we go about testing this class? Here’s how we would do it:
Let’s go ahead and add this file to ‘/tests/Unit’ folder.
Let’s run this test on the command prompt:
Great, 1 test passed with 3 assertions. Two assertions are the same as before on line 27 and 28. And one more new assertion is that of Mockery on line 19.
On line 5 we declare that we will use Mockery class with reference ‘m’.
Line 6 is a new change. Instead of using the default PHPUnit TestCase, here we use Mockery’s TestCase. This is so that Mockery can carry out Mockery specific assertion verification and cleanup the process after each test call.
For readers who have used Mockery before, you may be confused. Previously you’d have to run m::close() on tearDown() method for each test class. This has changed since Mockery v1.0.0 . You do not need to do that if you instead extend the Mockery’s TestCase class or use it’s trait. More info regarding this here: (http://docs.mockery.io/en/latest/reference/phpunit_integration.html)
And now something completely different. A picture of a relaxing red panda. Hey, we all need breaks. The reader deserves one and so does the writer. :D
Aww, isn’t it cute? :) I hope you don’t feel like the panda currently. Snoozy mode. Haha, we’ve still a bit more to go. Ahem, now back to what we were doing... Uhh, what was it? Oh yes, mocking objects left and right! Here we gooo..
Line 12 is where we make a mock object having the namespace of “App\Calculate”. This namespace has to be same as the original “Calculate” class, or else it will throw an error.
Then on line 14 we pass that newly created mock object to the new instance of Math class.
Now on line 19, is where the Mockery specific assertion begins. Now, we assert that the calculate class should receive the ‘areaOfSquare’ method call and we’ll return 4 when it does. And it should only be called once throughout the test execution, or it will fail. If you want it to run twice you can do ->twice() or times({number}) for any number of times.
There are different ways and techniques to declare expectations according to your need. I encourage you to check the official documentation for the full reference at http://docs.mockery.io/en/latest/reference/expectations.html
That was it for the introduction and usage of mocks. Hurray! Now we know how to use mocks! We can now mock them pesky dependencies left and right as we please. :D There are still a lot more to learn regarding mocks, but what we have is enough for our use case. We will be using it extensively on the next episodes as we go on to tackle TDD.
On the next episode, we will go and learn about Integration tests. The tests that do not deal with mocks, but rather call the real implementations.
If you have any questions or queries, please leave them below on the comment section.
Stay tuned. Don’t forget to give some claps to this article! And please subscribe to get notifications to new episodes ;).
Check out my other series at: