Author avatar for jason

Unit Testing with SugarCRM and PHPUnit

Posted by on October 11, 2012

Today's guest post comes from . Matt is a Senior Developer at Highland Solutions (a SugarCRM Gold Partner) in Chicago. When Matt isn't preaching about test driven development on Twitter as @mfrost503 he is writing about it and other various topic on his blog ShortWhiteBaldGuy.com. Have your own tips for creating top-notch solutions? We'd love to hear from you.

The ability to customize SugarCRM extensively makes it a very powerful application framework. Building modules, custom views or logic hooks can introduce bugs into an otherwise stable installation; luckily there's a way to improve the quality of the code you're writing in the development process.

Let's be honest, no one likes bugs and the sinking feeling you get in your stomach when a user finds a bug in something they're paying for can flat out ruin your day. We can combat the unexpected bugs with a healthy dose of testing. Testing often means a lot of different things to people; some people think of testing as running through the feature in the browser and validating a set of expected use cases and others use a wide variety of testing tools to ensure they're code is doing what is expected. Not testing your code is not an option, if you find yourself in that situation; there's no better time than right now to make some changes and improve the quality of your code and applications.

Unit Testing

What is unit testing? Unit testing is testing individual units of code in isolation to ensure they are functioning as intended. The idea of testing code in isolation can be confusing to some, so let me preface the idea with this: not all code is testable with a unit test. Writing testable code takes practice and it takes experience, it will take more time and is not for the faint of heart. Now that we have a pretty basic definition of unit testing, how do you do it?

PHPUnit is the industry standard testing framework and luckily for us SugarCRM has a configured unit testing framework available for us to use. One of the challenges to setting up an efficient testing environment is bootstrapping your tests so you're dealing with a similar environment. SugarCRM provides this with the framework.

Helpers

We know that we have a testing environment ready for us to use, how do we start testing modifications, logic hooks, etc? For most of the modules, there are helpers that will create instances of the bean you are trying to test. So, as you might expect, the Account helper is going to set up an account bean for you and the other methods attempt to clean up when you've finished. The beans that are generated from the helper have the same functionality as the beans in the application; so you can run save, retrieve, load_relationship, and any other method in your test. There are also methods to remove test data that's been created by saving beans.

Setup and TearDown

PHPUnit provides you the ability to have a setup and teardown method that get called at the bookends of the tests. So a single test class may have multiple tests, setUp will get called before your test runs. This gives you the opportunity to instantiate your bean and perform any sort of preliminary operations and/or setup so the actual tests can remain focused on testing. The tearDown method will clean up after your test, this is where you might call the method to delete all the created and saved beans and unset other values that may have been set during your test. The work that you do in the setup and teardown areas should be code that would be otherwise duplicated and thus prevent you from writing it in an the individual tests.

Tests

Up to this point everything that we've done has been configuration and setup to make sure that we can write the tests effectively and efficiently. While there are certainly different strategies for writing tests, this is the point where I like to talk about Test Driven Development or TDD. The idea basic idea behind TDD is that the tests are written first, the tests are supposed to initially fail and that the code you write ultimately causes those tests to pass. The tests themselves use assertions to verify that the code has performed as expected.

Here is an example scenario to drive this point home and make it a bit less abstract and ideological. Let's assume you have a requirement when a user saves an account that the DBA name is automatically populated with the Account Name. Since you know what you are starting with and what you are expecting to end with, you can write your test before you write a single line of code. "Given that the Account record is saved then the dba_c field should be populated with the value of the name field". You just write the assertions to make sure that happens! Piece of cake.

Practice Makes Perfect

As with anything new, this is going to seem counterintuitive at times. Heck, it's going to be downright annoying because you're probably not going to be very good at it right out of the gate. That's ok! You can develop the discipline to write the tests when it seems like a waste of time and know deep down that verifying that your code is doing what you want it to is not wasted effort. There will be tasks that "are too easy" to justify writing tests for them. Most experienced SugarCRM developers could probably meet the business requirement in the above scenario pretty easily. Write your test anyway, writing easy tests and getting results early on can be a great encourager and prepare you for that complex requirement that's lurking around the corner.

If you could tell your clients that your code will work and you can prove it and verify it internally, don't you think your customers will be happier? There's a pretty good chance that you're spending the extra time anyway, probably not up front and probably not with a predefined purpose. Writing automated tests, whether they're functional, integration or unit tests (some of the Sugar tests fit in all these categories, some more than others) will make your team proactive instead of reactive and improve the quality of your code. Who wouldn't want that?