Sunday, March 15, 2015

@testSetup - Create Common Test Data Efficiently

With Spring '15 release now you create common test records once and access them in every test method in the test class. All methods that are annotated with @testSetup will be called test setup methods.

Syntax for Test Setup Method (@testSetup annotation)
@testSetup static void methodName() {}

Let's take an example. You need to create an Account and a Contact record in Apex test classes (@isTest).


// Test Data Factory class
@isTest
public class TestDataFactory{
    public static Account createAccount(String accountName, String accountIndustry){
        Account acct = new Account();
            acct.Name = accountName;
            acct.Industry = accountIndustry;
        return acct;
    }     

    public static Contact createContact(String contactFirstName, String contactLastName, Account acct){
        Contact cont = new Contact();
            cont.FirstName = contactFirstName;
            cont.LastName = contactLastName;
            cont.AccountId = acct.Id;
        return cont;
    }
}


// Main Test class to create Account and Contact
@isTest
private class AccountContactTest{
    @testSetup static void setupCommonData(){
        Account acct = TestDataFactory.createAccount('Salesforce.com', 'Technology');
        insert acct;
        Contact cont = TestDataFactory.createContact('Marc', 'Benioff', acct);
        insert cont;
    }
    
    @isTest static void testMethodOne(){
        Account queryAccount = [SELECT Id, Name, Industry FROM Account WHERE Name = 'Salesforce.com' LIMIT 1];
        System.assertNotEquals(null, queryAccount);
        System.assertEquals('Salesforce.com', queryAccount.Name);
        System.assertEquals('Technology', queryAccount.Industry);
        
        queryAccount.Name = 'Facebook';
        update queryAccount;
        System.assertEquals('Facebook', queryAccount.Name);

        Contact queryContact = [SELECT Id, FirstName, LastName FROM Contact WHERE LastName = 'Benioff' LIMIT 1];
        System.assertNotEquals(null, queryContact);
        System.assertEquals('Marc', queryContact.FirstName);
        System.assertEquals('Benioff', queryContact.LastName); 
        
        queryContact.FirstName = 'Mark';
        queryContact.LastName = 'Zuckerberg';
        update queryContact;
        System.assertEquals('Mark', queryContact.FirstName);
        System.assertEquals('Zuckerberg', queryContact.LastName);        
    }

    @isTest static void testMethodTwo(){
        Account queryAccount = [SELECT Id, Name, Industry FROM Account WHERE Name = 'Salesforce.com' LIMIT 1];
        System.assertNotEquals(null, queryAccount);
        System.assertEquals('Salesforce.com', queryAccount.Name);
        System.assertEquals('Technology', queryAccount.Industry);
        
        queryAccount.Name = 'Google';
        update queryAccount;
        System.assertEquals('Google', queryAccount.Name);

        Contact queryContact = [SELECT Id, FirstName, LastName FROM Contact WHERE LastName = 'Benioff' LIMIT 1];
        System.assertNotEquals(null, queryContact);
        System.assertEquals('Marc', queryContact.FirstName);
        System.assertEquals('Benioff', queryContact.LastName); 
        
        queryContact.FirstName = 'Larry';
        queryContact.LastName = 'Page';
        update queryContact;
        System.assertEquals('Larry', queryContact.FirstName);
        System.assertEquals('Page', queryContact.LastName); 
    }    
} 

Note: All changes will be Rollback to the common setup data before starting a specific test method.

Benefits:


  • Create common test data easily and efficiently.
  • Reduce the number of lines of code.
  • Reduce test execution time.
  • It can be time-saving when you need to create a common set of records that all test methods depends on.
  • Use system resources more efficiently (Because now system would just need to roll back data from a single test method instead of roll back for each test method).

Considerations:


  • If a test class contains a test setup method, the test setup method executes first, before any test method in the class.
  • Records that are created in a test setup method are available to all test methods in the test class and are rolled back at the end of test class execution.
  • If a test method changes those records, such as record field updates or record deletions, those changes are rolled back after each test method finishes execution. The next executing test method gets access to the original unmodified state of those records.
  • It takes no arguments, and return no value. @testSetup static void methodName(){}
  • @testSetup method only works with the default data isolation mode "@isTest(SeeAllData=true)" for a test class.
  • It does not work with "@isTest(​SeeAllData=​true)". Because data isolation for tests is available for API versions 24.0 and later, test setup methods are also available for those versions only. Otherwise you will get an error: Test class containing a test setup method cannot be annotated with @isTest(​SeeAllData=​true)
  • Multiple @testSetup methods are allowed in a test class, but the order in which they’re executed by the testing framework isn’t guaranteed.
  • If a fatal error occurs during the execution of a @testSetup method, such as an exception that’s caused by a DML operation or an assertion failure, the entire test class fails, and no further tests in the class are executed.
  • If a @testSetup method calls a non-test method of another class, no code coverage is calculated for the non-test method. 

See further details for @testSetup method