Even if you do not have access or choose not to use the Sugar 7 PHPUnit framework, readers should still find the concepts covered in this post useful for testing Sugar 7 code.
Testing a Logic Hook
We will start with a realistic code customization so we can create a useful example of some unit tests. There are a variety of server-side code customizations that are possible within Sugar 7 but perhaps the most common example would be the Logic Hook. If you’ve done any significant amount of development on Sugar then you’ve like likely written more than one logic hook. Sugar logic hooks have been an important tool in the Sugar Developer’s toolbox since well before the release of Sugar 7. So this is a very appropriate example for us to use.
Below you will see an example of a before_save logic hook for the Accounts module. If you read the code, the use case is quite simple. When an Account record is saved we check the current account type and if it is an Analyst account then we set the Account’s industry to be Banking. This is accomplished with only a handful of lines of code.
You can install this logic hook locally by copying AccountsOnSaveHooks.php to the custom/modules/Accounts directory and copying setIndustryOnSave.ext.php to custom/Extension/modules/Accounts/Ext/LogicHooks directory.
Creating our first PHPUnit test
If you follow the steps to deploy the Sugar 7 unit tests (for example, here are the steps for installing unit tests in Sugar 7.6), you will have a test/ directory that is added to your Sugar 7 installation that includes many test files. You will also have PHPUnit installed under the vendor/ directory.
By convention, the tests/ directory mirrors the file structure of the rest of the Sugar application.
This means that when creating tests for our AccountsOnSaveHooks class, we will be creating them within a new file under the tests/custom/ directory.
To try our Sugar 7 PHPUnit test example, copy AccountsOnSaveHooksTest.php below to tests/custom/modules/Accounts/ directory. This file contains a new AccountsOnSaveHooksTest class where we have implemented several unit tests.
You can run these tests by using the phpunit executable installed under the vendor/ directory. You do need to make sure that tests/ is your current working directory when you run Sugar 7 PHPUnit tests otherwise it will not work
$ cd tests/ $ chmod +x ../vendor/bin/phpunit $ ../vendor/bin/phpunit custom/modules/Accounts/AccountsOnSaveHooksTest.php
Your output from this command should look similar to this example below.
PHPUnit 4.1.4 by Sebastian Bergmann. Configuration read from /Users/mmarum/Sites/SugarEnt-Full-188.8.131.52/tests/phpunit.xml.dist .... Time: 341 ms, Memory: 53.25Mb OK (4 tests, 15 assertions)
Some Sugar 7 PHPUnit framework features
There are a couple of features that we should call to your attention in the above example.
All of your Sugar 7 PHPUnit tests should extend the Sugar_PHPUnit_Framework_TestCase class. This class provides a wrapper that ensures your test behaves consistently as well as enables the use of SugarTestHelper functions.
SugarTestHelper is the utility that you should use to mock out your necessary test dependencies. For example, if you need to ensure that the $current_user is set to a valid value then you can use SugarTestHelper::setUp(“current_user”) to create a dummy user for the purposes of your test and ensure that it is removed after your test is complete. Inspecting tests/SugarTestHelper.php will reveal all the different utilities available to you as you write your tests.
Advice for creating good Sugar 7 PHPUnit tests
For this example test, we could have tried to set it up so that we call $bean->save() in order to trigger the before_save logic hook indirectly. This can seem like a reasonable approach because normally we would never call a logic hook function directly. However, calling the save() function on a bean has other side effects. For example, we could end up trigger multiple logic hooks when we are only interested in testing one for any given unit test. We could also end up writing changes into the database that we would need to be cleaned up afterward. Such DB writes will slow down the speed of your test execution considerably as your test suite grows.
Avoid causing DB transactions in your unit tests!