Structuring unit tests

In general, there is only one overarching pattern for unit testing code on the Salesforce1 platform. The essential differences between the Salesforce1 platform and other software development stacks does make unit testing is a bit different. That said, if you're familiar with unit testing in other languages, this will largely seem familiar to you. Here's the general pattern:

Structuring unit tests

Using your own data

Each of our test methods needs to create its own test data. While this seems cumbersome and time consuming, it's the only safe way to run unit tests. Relying on existing data in your org is problematic because you cannot ensure that the data will exist in your other orgs. Assuming an account will exist in your production org just because it exists in your development sandbox is a great recipe for frustrating deployments. This often finds its way into our tests through the use of hardcoded IDs. Querying for an account where the ID is X, for instance, not only assumes that the account exists in other orgs, but also that its fields contain the same values, including the ID field.

While creating your own test data can seem cumbersome and time consuming, there are a couple of things you can do to help with that. First and foremost, use a test factory. Test factories provide easy-to-remember methods for generating your test data. Additionally, they reflect the metadata of your org at runtime, allowing the test factory to dynamically know which fields are required and how to populate them intelligently. While there are a number of test factory libraries available, I'm a fan of Daniel Hoechst's Salesforce Test-Factory, which you can find on GitHub at https://github.com/dhoechst/Salesforce-Test-Factory. With his test factory in place, generating your own data for your tests is as simple as a call, like this:

// Calling TestFactory will pre-fill all the fields we need
Account a = (Account)TestFactory.createSObject(new Account());
insert a;

// You can also manually set specific values to be used. 
// Any values set in the constructor will override the defaults
Opportunity o = (Opportunity)TestFactory.createSObject(new Opportunity(AccountId = a.Id));

// You can also specify a specific set of overrides for different scenarios
Account a = (Account)TestFactory.createSObject(new Account(), 'TestFactory.AccountDefaults');

// Finally, get a bunch of records for testing bulk
Account[] aList = (Account[])TestFactory.createSObjectList(new Account(), 200);

// You can optionally insert records as created like this:
// Note the final parameter of true.
Account a = (Account) TestFactory.createSObject(new Account(), true);
Contact c = (Contact) TestFactory.createSObject(new Contact(AccountID = a.Id), true);

Even with a test factory in place, it can be cumbersome to have twenty lines of code in each test simply setting up data. Here's where the second tip comes into play. While the test factory can provide specific sObjects for us, we often need a collection of related objects to test with. For instance, we may need an opportunity with opportunity line items associated with it for our test. Normally, that would require creating not just the opportunity and opportunity line items but also the account and any contacts we may need. In these situations, it makes sense to establish one or more customized test factories that rely on and build on the functionality of the basic test factory. I like to ensure that everything is easy to find, so I tend to have many sObject specific test factories. Consider the following instance:

@isTest
Public Without Sharing Class OpportunityTestFactory {

  Public Static genOppWithLineItemsAndAccount(Integer numLineItems, Boolean doInsert){
    Account a = (Account)TestFactory.createSObject(New Account(), 
      doInsert);
    Opportunity o = (Opportunity)TestFactory.createSObject(New 
      Opportunity(accountId=a.id), doInsert);
    List<OpportunityLineItem> olis = new List<OpportunityLineItem>();
    for(Integer i = 0; i < numLineItems; i++) {
      olis.add((OpportunityLineItem)TestFactory.createSObject(new OpportunityLineItem(OpportunityId=o.id)));	
    }
    if(doInsert){
      insert olis;
    }
    return o;
  }
}

These kinds of customized test factories grow over time but having them means it's easy to add additional custom methods and easier to write tests using your own data. Two tips on custom test factories. First, always annotate them as @isTest at the class level. This ensures that the code cannot be called in a non-test environment and that it doesn't count against your overall code coverage. Secondly, note how I've maintained the optional insert flag for the method in the preceding code. If your test doesn't rely on triggers and other data manipulation language (DML) based operations, you can often write faster running tests by not inserting or querying. Oftentimes, however, you will have to insert the data, and maintaining that simple Boolean flag in your custom factory methods makes it that much easier to do.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.17.12