Monday, December 16, 2013

Apex Test Methods - SeeAllData

One topic that I want to touch on is the SeeAllData attribute.  I thought to include it in my other post about test methods but decided to give this one it's own space.  First, let's get a definition on it:

***
Starting with Apex code saved using Salesforce.com API version 24.0 and later, test methods don’t have access by default to pre-existing data in the organization, such as standard objects, custom objects, and custom settings data, and can only access data that they create. However, objects that are used to manage your organization or metadata objects can still be accessed in your tests such as:
User
Profile
Organization
AsyncApexJob
CronTrigger
RecordType
ApexClass
ApexTrigger
ApexComponent
ApexPage
Whenever possible, you should create test data for each test. You can disable this restriction by annotating your test class or test method with the IsTest(SeeAllData=true) annotation.
Test code saved using Salesforce.com API version 23.0 or earlier continues to have access to all data in the organization and its data access is unchanged.

***

I've seen and heard many people claim that setting this attribute to true was a bad practice.  Go ahead and google it.  You'll find plenty of well-intentioned people telling you that you should never (or very rarely) set it to true and warn you like they were saving you from some kind of doom.

I say that there are plenty of reasons to use it and removing this from your tool set, puts you at a disadvantage.  Let's look at a couple examples of where I see some utility:

  • Existing org data
    • Volume
    • Quality
  • Custom settings
Setting SeeAllData to false (or accepting the current default), limits your test methods from existing org data. So for example, if you were to query for an existing account and set a field value in your test method, you'd end up with a query exception.  If you were the developer of a managed package, you'd probably be smart enough to recognize that this scenario and that your account doesn't exist in your customer's org, so you'd need to create a new account in your test methods.  In this case, SeeAllData = false, makes sense because you cannot assume that your test data exists in someone else's org.

If you were the developer of your company's internal Salesforce instance, your perspective and use cases are likely to be different. Imagine you've created a vf page that aggregates some account data.  For a page that does a lot of soql queries, you may be concerned about performance or governor limits.  If your org had millions of accounts, you could make your test methods try to simulate your account data volume, but it might be smarter to make use your existing data in your full sandbox also.  Running apex tests for both new and existing data, you'll be more confident in how your application behaves in production.  

Data quality is another place where setting SeeAllData = false may leave you vulnerable.  Let's say your org's history was something like this:
  1. In January, your users started using opportunities
  2. Later in March, they created a validation rule to make a field required on opportunities
  3. In June, you were asked to come in and add a trigger to activities to automatically update the related opportunity
If you were using SeeAllData = false, your test methods would create a new account and opportunity, create a related Task, and successfully assert that the Opportunity was updated by your new trigger.  Your test opportunity would have been created with all of the required data and your trigger would pass your unit tests.  However, the trigger would fail in production, perhaps unexpectedly, because you didn't know that there were January opportunities that had not been updated after the validation rule was introduced.  If you were using SeeAllData = true, you may have caught this data inconsistency and been prepared to handle the exception cleanly.

I think custom settings are another place where I'd look to use the SeeAllData.  In much of my apex code, I try to make the code flexible through a custom setting.  So, for example, if I am integrating via an http callout, I'd try to put the endpoint url in a custom setting.  Using SeeAllData = false, I could succesfully deploy to production without ever setting up the custom setting because my test methods create the custom setting. However, using SeeAllData = true, my test methods would fail because the custom setting had not been created in production.  This allows me to be sure that my dependency is in place before bringing users back into the system.  

So, there you have it.  SeeAllData = true can be your friend.  It's like bacon - plenty of people will tell you to avoid it, if you want to live.  But I say a little bit in your life can be delicious.
  

Deep Thoughts on Apex Test Methods

You're good enough.
You're smart enough.
You can write a good apex test method.

I just completed a major rewrite of all test methods for a client and while it was painful at times, I think it puts them in a position to extract some value from what was previously just a production deployment hurdle. Trust me, I'm not yet a full test-driven-development convert but I do believe that you can help your business automate some testing, and maybe even save some cash, if you take the time to think about your testing and apply it to your test methods.

You get better at the things you do over and over and writing good test methods is certainly something you can expect to have plenty of opportunity to practice.  There are some great resources out there to be sure you are repeating good habits. I'd start with Dan Appleman's Advanced Apex book as he has some great ideas for test class writing. Some other articles that I think are helpful and instructive are:

http://jessealtman.com/2013/09/proper-unit-test-structure-in-apex
http://wiki.developerforce.com/page/How_to_Write_Good_Unit_Tests

With this recent rewrite effort, some of the good practices I've incorporated are:

  • Moving test methods from functional classes into separate Test Classes
    • This allows you to decouple your tests from your functional classes, which excludes your tests' ability to reach private methods.  This will give you some flexibility with refactoring your code without being tied down by your test methods.
  • Asserting results
    • While you may achieve the 75% goal of code coverage, your tests will have little/no value if you are not actually checking expected versus actual results.  As a managed package developer, you'll also get flagged during the security review if you are not asserting your results. 
  • Centralizing and standardizing helper utilities
    • Like other apex you write, you should try to encapsulate where you can and use helpers to minimize the effort in testing various permutations of data against your code.
  • Testing negative scenarios
    • This is another area where you can get some value out of unit testing.  While it may take 80% of your effort to identify and code these, it's going to yield lots of value in improving your code and confidence in your code handling atypical scenarios.
  • Testing as an end user
    • Unfortunately as developers, we are system admins and almost everything we test works as expected because we don't have to deal with sharing or role hierarchy or object/field visibility. However, in the real world, our users are almost never system admins, so testing as a system admin makes no sense.

This is certainly not the complete list of best practices, but it's a good start.

As with other things in Salesforce, there is some room for improvement with the execution of unit testing in the application. In particular, I'm still frustrated by what Jeff Douglas calls the "black art".  Like Jeff, I've come across some peculiar behaviors that can be maddening.  For example, if you are testing a trigger and need to create a user and then test the dml, there's a pretty good chance you're going to get a mixed DML exception.  What is maddening, however, is that the error will not be caught in the force.com ide.  Oh, and you can deploy to production with this too!  The only thing keeping me sane was knowing that someone else noticed this too:



And aside from the nonsense of trying to estimate your code coverage in any of the tools out there, it would be nice if the test classes had the code coverage estimation like the functional classes for those of us separating them:


And don't get me started on the new test execution screens.  Aside from queuing your tests, they provide no value!

I think there is plenty to like about putting some effort into doing proper unit testing in Salesforce.  I'm sure if you build in the time to your sprints/plans, it will pay dividends in the long term.  Just be sure you approach this with a good sense of humor.


Wednesday, November 20, 2013

Traffic Nightmare @ Dreamforce

This is incredible..last year, the SF Giants were in the playoff hunt so downtown was already jamming. I can't even imagine trying to drive anywhere with over 140k registered attendees this year:

Monday, November 18, 2013

Drink the Kool Aid, It's DreamForce Season Again!

Salesforce1 appears to be the big announcement this year.  I just watched this video that Salesforce published and while the music and voice over are great, I don't understand a thing about what is being announced.  If you can make sense of this video, please share in the comments.


Wednesday, November 13, 2013

A Bug!

It's not often that I come across a real bug with Salesforce's apex or visualforce platform.  Most often there are limitations or shortcomings that you have to workaround.  Recently, I had to make an urgent change to a trigger and it's associated test class.  However, when I attempted to comment out a line in my test class, I got the following error in the editor when I tried to save:

java.lang.reflect.InvocationTargetException

When I attempted to make the same change in the developer console, I got another error:

 An unexpected error has occurred. 421011484-16071 (1420197083) for deploymentId=1drJ00000002FDxIAM If this persists, please contact customer support.


Fortunately, I was able to still deploy my code without the test class change but I opened a case anyway and after waiting a few days for a reply, was told that it was a known issue.  The instructions from developer support were:
  • Please clear Test results and try to save the code:
    • From Setup, click Develop | Apex Test Execution |View Test History | Clear test results. 

However, even before I did these actions, I tried to update the test class again and surprise!  no errors. So, something fishy is going on... Support wants to close the case but I'm inquiring for additional details.  Will keep you posted.


**Update Nov 13**

Salesforce has responded and indicated that it was a bug but has been fixed.  Details here: https://success.salesforce.com/issues_view?id=a1p30000000T17j

Friday, November 8, 2013

Workflow and User Permissions

Q: Do workflow rules run as the user or do they run as the system?  For example, if you had a sales team associate update an opportunity and there was a workflow that fired on any opportunity edit, would the workflow update a field that the user did not have profile (or permission set) permission to update?

Q: If the workflow action reassigned ownership to another user, would it execute the ownership change despite the user's system permission of Transfer Records as false?

Q: If the workflow action changed the record type to a value, would it change the record type if the user's profile did not have access to the specific record type value?

***

My initial reaction was that workflow would run as the logged in user and would obey the user's profile and permission sets.  However upon testing, what I found was that workflow runs as the system and does not honor the user's profile or permission.  So, for the 3 questions above:

  1. Workflows run as the system and would update a field that the user did not have profile/permission set access to update
  2. Workflows will execute ownership changes on behalf of users who do not have permission to directly change the ownership
  3. Workflows will change record types in spite of profile-specified record type access.



Wednesday, October 30, 2013

JQuery Tablesorter, Meet PageBlockTable

I am definitely late to the jquery party.  In the last year or so, I've been able to harness jquery to make pages more usable and functional and just finished a poc for another beautiful jquery solution for a recurring visualforce requirement: sortable tables.

A colleague and I were doing a peer review on a visualforce page he had built.  The page had a sortable pageblocktable, which he had enabled with a custom compare function he had built in his controller.  Now, I've seen all kinds of ways of doing sorting in the controller and have done some suboptimal server-side sorting, but I never really thought about trying to keep it client-side.  I figured there'd be a way with javascript but I just didn't have it in me to try to code it up.  So, I poked around the google and sure enough, there's a jquery plugin already built to do it.  And, sure enough, another Salesforce developer, shared her solution using the tablesorter plugin years ago.

So, a few years late to the party :)

Anyway, I wanted to share my variation since I was able to get the tablesorter to work w/ the standard apex component pageblocktable.  Again, with jquery, the solution is basically the following:

1. Import your library as a static resource
2. Reference your resource in your vf page
3. Bind your jquery function and your component

So, applying the parts to my poc, I have a page that looks like this:

*******

<apex:page standardController="Opportunity" tabStyle="Opportunity" extensions="myext" id="thepage">
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/>
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"/>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/ui-lightness/jquery-ui.css" type="text/css" media="all" />
<apex:includeScript value="{!URLFOR($Resource.tablesorter, 'jquery.tablesorter.min.js')}"/>

<script type="text/javascript">
    $j = jQuery.noConflict();    
    $j(document).ready(function () {
    $j("[id$=theaddrs]").tablesorter();

    });

  //some other unrelated js

</script>

<!-- some other visualforce stuff then the heart of the proof of concept: -->

<apex:pageBlock id="theaddrsblock">

                    <apex:pageBlockTable value="{!Addrs}" var="a" id="theaddrs" styleClass="tablesorter" headerClass="header">
                    <apex:column>
                            <apex:facet name="header">
                                <apex:outputText styleClass="header" value="{!$ObjectType.Address__c.Fields.Street__c.Label}" />
                            </apex:facet>
                            <apex:outputText value="{!a.Street__c}" />

                        </apex:column>

<!-- the other columns, closing tags, and that's it -->


******

There is nothing to share about the controller because the sorting is being done w/out a callback to Salesforce.

The sections highlighted in yellow show how little is needed to modify your standard pageblocktable into a sortable table.  Not much, right?

I suggest looking at the documentation or online discussions about optional parameters that can be specified in the tablesorter library but if you just have a few fields in a table that you need to sort, the tool will do a great job of figuring out the data magically.  It's really awesome.

Now, this is only a proof of concept and so there is at least one issue resolve:  the icons to indicate sort direction are displaying on top of the column labels.  Should be able to modify the css to offset the icons.  Worst case, we just remove the styleClass attribute on the outputtext of the column facet.  Anyway, if you don't have to send it back to the controller for some logic or because the dataset is too large, just use the plugin to sort!