Search

Monday, 7 May 2012

SeeAllData annotation in Spring 12 Salesforce Release

SeeAllData annotation opens up a number of interesting things to think about.

Of course when unit testing a good developer will create his/her own test data to ensure that your unit tests will equally work in environments (live and sandbox) where there is not enough sufficient data to test.

So with API 24 SeeAllData is set to False as standard, where test methods don’t have access by default to pre-existing data in the organization.
So that's good, right?
Well yes and no. It is also important to test under conditions where there is a lot of data to ensure that your tests equally work. Have you ever come across situations where your unit tests work in your developer sandbox, you deploy to the Full UAT Sandbox and you find that your unit tests no longer work.
This can happen because of many reasons, soqls designed with no limits, limits on soqls are too restrictive and don't pick up the intended data, triggers work on a small number of records, but break on bulk uploads of say 200 records and so on.
So if you only test where SeeAllData is set to False this won't fully test your classes.

So I suggest you create 2sets of unit test methods 1 where SeeAllData  is False, 1 for True. Test methods will be exactly the same, but creation of test data is different.


The isTest(SeeAllData=true) annotation is used to open up data access when applied at the class or method
level. However, using isTest(SeeAllData=false) on a method doesn’t restrict organization data access for that
method if the containing class has already been defined with the isTest(SeeAllData=true) annotation. In this
case, the method will still have access to all the data in the organization.



Say you are testing an insert trigger on the Account.


Set your class to be SeeAllData=false, which is default


Set TestMethod SeeAllData  is False is quite straight forward
Test your classes under an data empty environment, so you need to create
Account thisAccount = new Account(Name='Steves test account');
insert thisAccount;

Set TestMethod SeeAllData  is True
Test your class under full data conditions to ensure your classes still work.
First identify how many Accounts currently exist in the system, there's no point in making the system create more Accounts than it needs to.


Account[] thisAccountTest = [select Id from Account limit 200];
Account[] newAccs = new Account[]{};
if (thisAccountTest.size() < 200){
      for (integer i=0; i<=200 - thisAccountTest.size() ; i++){
             newAccs.add(new Account(Name='Steves test account' + i));
      }
       insert newAccs;
}

You may ask why not just create tests where SeeAllData  is True and create all the Accounts you need to.
Well it's slower to run this test so when you are deploying new code to the live environment this will slow down each deployment. The answer is to force your unit tests to run your test methods that are annotated SeeAllData  is True only during deployment to the live environment and other deployments will only run SeeAllData  is False test methods.
At the moment it's quite difficult to stop SeeAllData is True tests running only on deployment, so the best alternative approach at the moment is to first Validate all your code to Live environment with the SeeAllData is True test class included. So long as your validation passes, now deploy your code without the SeeAllData is True test methods.
I suspect that Salesforce will at some point allow you to run certain test classes only at deployment, but for now this is not possible.

Note:

Test code saved against Salesforce API version 23.0 or earlier continues to have access to
all data in the organization and its data access is unchanged. So if your environment contains a lot of data your tests will run much slower.

Thursday, 3 May 2012

Autonumbers Increment In Unit Tests

Autonumbers increment when running a testmethod in unit tests. So we you go back to the real world the next number produced by an auto number field is 1 more than previous.

Surely not you say.

Sorry, but true. So how do you change this. You have to turn off a setting in salesforce, so you will have to raise a Salesforce Case to set a flag to default=off on specified custom objects.

For more information review 
http://success.salesforce.com/ideaView?id=08730000000Br67AAC