Testing Best Practices

I’ve said it before–I’m not a software developer. I’m a hacker who got into this line of work via a circuitous route that never went through a comp sci class room. OK, that’s not true. I took one C class at the UW and quit midway through.

So now I’m writing lots of Salesforce code and as our complexity has increased I’ve had to get systematic about it. Part of the puzzle I had to learn from scratch was Testing.

Here are my top testing best practices with Salesforce.com that I learned on the job. Please comment if I’m misguided or skipping something of import.

Write fully portable tests

When you write your tests, you do so in the context of a Developer or Sandbox org. You can write tests that rely on specific pieces of data, user accounts, server names, etc. If you do that, however, your tests will fail on deployment because those things will be different in the destination organization.

Use relative URLs and query for names of data records rather than their specific Ids. Then if your tests pass in the sandbox, they are more likely to behave as expected no matter where you put them.

Don’t use production data in your tests

On a related note, if you do SOQL statements in your tests, those queries will return results from the Salesforce instance. So, if you SOQL “Id from Account where Name =’Microsoft’”, you will get one result in Sandbox and another in Production. When you set up test data, make sure to use names that will never show up in production, like “Microsoft_for_tests” as an example Account Name.

Test expected behavior first, then test unexpected behavior

Start with testing simple cases, and test to make sure that what what you expect to happen is indeed happening. Then make sure to add test cases for behavior you don’t expect, but could happen. This is why they tell developers never to write their own tests, because we all believe our code will behave as expected. Fight that urge, and test around the edges to make sure you’re covering yourself.

If you find a bug, write a test to expose it before you fix it

When someone reports unexpected behavior in your code or UI, write a test that will find the bug and fail. Then fix the code until the test passes, and leave the test in. By putting the test in there first, you’re doing test-driven development for this fix, which is a great practice to get into. If you leave the test in there, you’ve also now got a regression test in case you accidentally reintroduce that bug later.

Shoot for 100% coverage

Try to test everything. It’s not always fun or even possible, but try.

Don’t rely on Today()

If you are using dates in your code, don’t build your dates on Today(). Rather, use something like Date.newInstance(2005,10,10). By putting a date in the past, you don’t have to worry about what will happen to your test when you try to run it on February 29th, or the instant we hit daylight savings time. If you think those cases will affect your code materially, you should specifically test those cases, but most of the time you’re safe to ignore that by not using Today().

Put your tests on the controller and class, not in separate classes

We’ve found it easier to ship code around when the test methods are on the controller classes. It’s fewer files to keep track of, and when you deploy to production, you’re tests are automatically included in the package, ensuring code coverage.

Please comment if you’re interested in having a discussion about testing in Salesforce.com. I love and hate that they require 75% code coverage for deployment to production–it sure pays off in the end, but it can be quite a drag when I’m struggling with a stupid syntax problem in a test.

10 Responses to “Testing Best Practices”

  1. Scott Hemmeter Says:

    Regarding test data, I’d recommend actually creating the data as part of your Test Class. Salesforce creates it for the purposes of the test only and it never goes in the org. This takes more work, but makes it fully portable. This might be what you meant in your post, but I wasn’t totally sure.

    Use the @IsTest keyword. I think this means you need to put your Tests in separate classes, though. Adding this keyword makes it so the test code doesn’t count against your code limit. This may not matter if you are not coding heavy amounts.

  2. Steve Says:

    Yes, that’s the way I do it. Sorry it wasn’t clear. If you create an Account in your test data, make sure it has a funky name if you ever are querying it by name. That was the point I was trying to make. 90+% of the time we’re getting records by Id, but in a couple cases I’ve needed to query by name.

    @IsTest is the same as testMethod, but it appears it does except that code from the total 1 MB limit for all Apex code. Glad I’m not anywhere near that big!

  3. Mike Says:

    I’d say you’re in the top 20 percentile of all Software Developers if you’re consistently implementing these practices.

    Like most software dev projects, long term success is defined by low cost-of-change over time (aka ‘Agility’).

    Some things I’m conscious of when coding with unit tests:
    * Test-Driven-Development: Write a unit test first that most elegantly documents the desired object interfaces and control flow, then write actual classes to make the test pass. This qualifies as formal ‘design’ in agile projects.
    * 500 line rule. Time to refactor if any file/class gets over 500 lines.
    * 5 minute refactoring rule. Approach larger problems as a series of smaller 5 minute refactoring drills; each with corresponding unit test changes (I dread refactoring lots of code then having to go back and clean-up tests).
    * Self-Documenting: Write tests as a means to describing and documenting the intended usage of the system. A self-explanatory method or test name is preferred over comments.

  4. Steve Says:

    Thanks Mike!

    These are great tips. I love them all and will be incorporating them in my daily coding practice (sounds like yoga when I say it that way…)

  5. Jesse Lorenz Says:

    I’m with Mike – TDD is great. Test Driven Development makes developers think about how clients will use their code straight away. As a result, they’re able to write code faster and have to refactor less often.

    The “Apex Test Coverage Best Practices” session from Dreamforce is a great resource for developers intrested in Unit Testing in general: http://www.salesforce.com/community/crm-best-practices/dreamforce08-developer-sessions/2008-tdf-mastering-apex-best-practices.jsp

  6. David Glick Says:

    Great stuff, Steve.

    On the Plone side, one point that I’ve found helpful is the distinction between unit tests and integration tests. Unit tests focus on a particular function and make sure that it behave properly for a range of different inputs. Integration tests test the system as a whole and make sure that everything is wired together properly. For the latter, we use the zope.testbrowser package which lets us write Python code that mimics a web browser and can click links, press buttons, etc. (no real rendering or Javascript support though — for that you need something like selenium)

    This post also raises the question — does ONE/Northwest have any developers who have taken a real CS course? I only lasted a day in the one I tried… :)

  7. Steve Says:

    Thanks Jesse. I had to miss that session because I was speaking in another. I forgot about it, so thanks for the link.

  8. Steve Says:

    Shhh David, some of our clients may read this blog…

    All my testing to date has been unit testing. One of the great things about VisualForce is that if I use standard components, all that integration testing should already have been done by Courtney’s team down at Salesforce!

  9. Reid Says:

    +1 on everything, glad to see it all here. One thing I would add regarding the question of what to test. Most developers test business logic that should lead a class or method to function successfully. I always like to see people test things that they think should fail. A missing parameter here or some bad data there, for example.

    FWIW, in addition to TDD, there’s a cool thing out there called Design by Contract or Programming by Contract. It’s not appropriate for every programming challenge, but it’s a useful frame of reference to have in your bag of tricks.

    Cheers!

  10. Steve Says:

    That’s an interesting concept. Thanks for the pointer to it!

Leave a Reply