Preface
A ladybug is beautiful, but a logical bug is not! The Logical error is a not new thing for the developers and it hampers the functions of any application. The faster the application is bug-free, the sooner it can get released for the end users. And the ‘bug-free’ journey starts with successful unit testing where the developers are solely responsible for the same.
Understanding Unit Testing
Unit testing is analyzing a small line of code in isolation. It should not be dependent on any functions or class. The below infographic explains the difference of class dependency in a real system and unit testing:
Image Credit: medium.com
A unit test should have the following characteristics:
- Anything that runs in memory.
- It should not touch any external resources e.g. database, file system or external API.
- It should be easily repeatable.
- It should be fast.
What is a Mocking Object?
In the English language, mocking means imitating or making fun of something. However, in unit testing mocking plays a momentous role by simulating an external environment to the independent scenario. The below infographic explains how the unit testing works with a mocking object:
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.
Whenever there is a need to use external resources in our code, we can use a mock object to replace this external resource in our test. Beforehand, every developer knows the requirement and output of the external resource. By creating an object that will take input and give output exactly as an external resource, we can use it in our test.
Benefits of mock objects
- A unit test can be isolated from their dependencies.
- The unit test will run quickly in case of mocking databases, file system or external service.
- Useful for testing external objects that produce nondeterministic results.
How does PHPUnit work?
PHPUnit provides methods that are used to automatically create objects that will replace the original object in our test. createMock($type) and getMockBuilder($type) methods are used to create mock object. The createMock method immediately returns a mock object of the specified type. You can use getMockBuilder method to customize the generation of a mock object using its fluent interface.
Use Case: Let’s consider that we are using a payment API to make payment to the shopping website. We require a function that will call authorize() function of payment API. It will return CONFIRMED status on the successful charging of the payment. If anything goes wrong then it will return DECLINED. We need to check the response and return a boolean value from our function.
We have not written our function yet. However, we will start with our test case.
testChargeConfirmed
After running our test, it fails as we have not written our function yet. Meanwhile, we will go through this test case function. This test function uses getMock() function to create a mock object of the payment class(Payment library class). It has set an ‘authorize’ function that is expected to be called one time and it will return the ‘CONFIRMED’ string. Then, we create an object of our class OnlineShop and call charge method passing payment object to it as a parameter. Finally, we are asserting the response from our function. It will mandate the authorize function is called only once if called more than that the test will fail.
Now we will create our function in OnlineShop class.
Another Test
After writing the above function our test is getting passed as in our test we have passed a mock object of Payment class rather than the original payment class. You need to recall that we have called charge() function in our test by passing a payment object to it. Since we have set return value as ‘CONFIRMED’ in our test.
For interacting with third-party resources, writing a log file in our file system and reading or writing it to our database are important. These operations are either out of our control or it is difficult to repeat. In such cases, if we use mock object then we are using system memory to read or write values. Therefore, it is very fast and easy to repeat.
Putting it all Together
Mocking object empowers your unit testing with a better output. It also helps in refactoring or restructuring existing computer code. Better code maintenance and a clean production environment are the results of an intelligent mock object unit test.