Showing posts with label @isTest. Show all posts
Showing posts with label @isTest. Show all posts

Saturday, March 21, 2015

Testing in Apex

“one unit test is infinitely better than no unit test”

Testing in Apex

Testing is an important part of the development process. Like other programming languages, Apex also provides a testing framework that allows you to write unit tests, run, check and have code coverage of your test results.
In Salesforce before you deploy Apex to your Salesforce.com Production organisation or package it for the Force.com AppExchange, you must have at least 75% of your Apex code covered by unit tests, and all of those tests must complete successfully. 

The most important point and advantage to create a separate class for Apex Test methods is that it does not count against your organisation limit of 3 MB for all Apex code. 

Apex Test Class Syntax:


// This class contains test methods with different data access levels.
@isTest
private class className{
    
    // Method 1
    static testMethod void methodName1(){
              // your logic here
    }
    
    // Method 2
    @isTest static void methodName2(){
              // your logic here
    }
    
    // Method 3
    @isTest (SeeAllData = true)
    static void methodName3(){
              // your logic here
    }
    
    // Method 4
    @isTest
    static void methodName4(){
              // your logic here
    }

}


// All test methods in this class can access all data of Salesforce organisation.
@isTest (SeeAllData = true)
private class className{
    
    // Method 1
    static testMethod void methodName1(){
              // your logic here
    }
    
    // Method 2
    @isTest
    static void methodName2(){
              // your logic here
    }
    Note: You don't need "@isTest (SeeAllData = true)" here because class has already been defined with the @isTest(SeeAllData=true) annotation.

}


First thing to notice is that we use the @isTest annotation. All classes marked with "@isTest" annotation will make classes to run in Testing context only. Also, you see we use "testMethod" keyword and "@isTest" annotation for defining methods within Test classes. Both are interchangeable the only difference is you can access your organisation's data by using "@isTest (SeeAllData = true)" annotation individually with the method.


Winter '12 Features for Apex Testing

With Winter '12 releaseForce.com platform provided you a capability to create Public test classes that expose common methods for test data creation. These public methods can be called by tests outside the test class for setting up data that the tests need to run against.

Methods of a public test class can only be called from a running test, that is, a test method or code invoked by a test method, and can't be called by a non-test request. 

// In this class you can create and expose records to called by other test classes
@isTest
public class TestDataFactory{

    public static Account createTestAccount(){
              // create test Account records
    }
    public static Contact createTestContact(){
              // create test Contact records
    }

}


Spring '12 Features for Apex Testing

Spring '12 release came with a feature "Isolation of Test Data for Unit Test". It means with Spring 12 release you can now explicitly mark your test class "@isTest (SeeAllData = true)" to access your Salesforce organisation data.

As we know all Salesforce metadata components associate to a particular Salesforce API version and every version has dependency based on features.

Spring '12 release came up with Salesforce API version 24.0 and announced that Apex code saved using Salesforce API version 24.0, test classes and methods don't have access by default to pre-existing data in the organisation. So, for Apex code saved using Salesforce API version 24.0 and later, use explicitly the @isTest(SeeAllData=true) annotation to grant test classes and individual test methods access to all data in the organisationBut Test code saved against Salesforce API version 23.0 or earlier continues to have access to all data in the organisation and its data access is unchanged.


Spring '15 Features for Apex Testing

Finally Spring '15 release has came up with a new annotation "@testSetup" which gives you ability to "Setup Test Data for Entire Class".
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)

@isTest
private class className{

           @testSetup static void commonmethodName() {
                               // your logic here
           }

           // Method 1
           static testMethod void methodName1(){
                               // your logic here
           }
    
          // Method 2
          @isTest static void methodName2(){
                               // your logic here
          }

}

For further details of @testSetup method see here


Considerations:

  • Use the @isTest annotation to define classes and methods that only contain code used for testing your application. The @isTest annotation on methods is equivalent to the testMethod keyword.
  • Classes and methods defined as @isTest can be either private or public.
  • Classes defined as @isTest must be top-level classes.
  • Classes defined with the @isTest annotation don't count against your organisation limit of 3 MB for all Apex code. 
  • Classes defined as @isTest can't be interfaces or enums.
  • Methods of a public test class can only be called from a running test, that is, a test method or code invoked by a test method, and can't be called by a non-test request.
  • You must have at least 75% of the Apex code coverage in your organisation to be able to deploy the code to your Salesforce production organisation.

Useful Resources:

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