Showing posts with label Test.startTest() and Test.StopTest(). Show all posts
Showing posts with label Test.startTest() and Test.StopTest(). Show all posts

Tuesday, November 20, 2018

Future Method and Mixed DML Errors in Salesforce.com

Future Method and Mixed DML Errors in Salesforce.com

When we perform DML on setup and non-setup sObject simultaneously then mixed dml errors occurs. 

To avoid mixed DML errors
1) Create a method that performs a DML operation on one type of sObject.
2) Create a second method that uses the future annotation to manipulate a second sObject type.

Apex Class

public class MixedDMLFuture {
    public static void useFutureMethod() {
        // First DML operation
        Account a = new Account(Name='Acme');
        insert a;
       
        // This next operation (insert a user with a role)
        // can't be mixed with the previous insert unless
        // it is within a future method.
        // Call future method to insert a user with a role.
        
UtilClass.insertUserWithProfileAndRole('username@abc.com', 'myAlias',
            'emailAddress@abc.com', 'Bill','Business Head', 'CEO');       
    }
}


Apex Future Method

public class UtilClass {
    @future
    public static void insertUserWithProfileAndRole(
        String userNameIs, String aliasIs, String emailAdd, String lastNameIs, String profileName, String roleName) {
        
//Get the profile Id 
        Profile profile = [SELECT Id FROM Profile WHERE Name=:profile];
//Get the role Id
        UserRole role = [SELECT Id FROM UserRole WHERE Name=:role];
        
// Create new user with a non-null user role ID
        User usr = new User(alias = aliasIs, 
            email=emailAdd,
            emailencodingkey='UTF-8', 
            lastname=lastNameIs,
            languagelocalekey='en_US',
            localesidkey='en_US', 
            profileid = profile.Id, 
            userroleid = role.Id,
            timezonesidkey='America/Los_Angeles',
            username=userNameIs);
        insert usr;
    }
}


Apex Test Class
============

Mixed DML Operations in Test Methods :-
The System.runAs() block runs in the current user’s context. It creates a test user with a role and a test account, which is a mixed DML operation.
Using Test.startTest and Test.stopTest to bypass the mixed DML error in a Test Method.

@isTest
private class insertUserWithProfileAndRoleTest{

    static testMethod void createTestUser(){

        Profile pro = [Select Id From Profile Where Name = 'System Administrator'];

        //Create setup sObject records (User)
        User usr = new User();
        usr.FirstName = 'First';
        usr.LastName = 'Last';
        usr.Email = 'first@test.com';
        usr.Username = 'astest@test.com';
        usr.Alias = 'first';
        usr.ProfileId = pro.Id;
        usr.TimeZoneSidKey = 'America/Denver';
        usr.LocaleSidKey = 'en_US';
        usr.EmailEncodingKey = 'UTF-8';
        usr.LanguageLocaleKey = 'en_US';
        insert usr;

        system.debug('usr is ' + usr);

        System.runas(usr){

            //Create non-setup records & run tests here
        }
    }
}












Asynchronous Apex: Queueable Apex in Salesforce.com

Queueable Apex

The best features of Queueable Apex is job chaining. If you ever need to run jobs sequentially, Queueable Apex is only option.

To chain a job to another executing job, submit the second_job by using execute() method of your queueable class. You can add only one job from an executing job, which means that only one child job can exist for each parent job. 

For example, if you have a second class called Second_Job that implements the Queueable interface, you can add this class to the queue in the execute() method as follows:

Queueable Syntax:

public class SomeClass implements Queueable { 
    public void execute(QueueableContext context) {
        //awesome code here
    }
}

Chaining Jobs:

public class FirstQueClass implements Queueable { 

    public void execute(QueueableContext context) { 

        // Awesome processing logic here   
        // Chain this job to next job by submitting the next job
        System.enqueueJob(new Second_Job());

    }
}


Note: Once again, testing has a slightly different pattern. You can’t chain queueable jobs in an Apex test, doing so results in an error. 
To avoid errors, you can check if Apex is running in test context by calling Test.isRunningTest() before chaining jobs.

Scenario 1:

The following apex code takes a collection of Account records, sets the parentId for each record, and then updates the records in the database.


public class UpdateParentAccountQue implements Queueable {

    private List<Account> accounts;
    private ID parent;

    public UpdateParentAccount(List<Account> records, ID id) {

        this.accounts = records;
        this.parent = id;
    }

    public void execute(QueueableContext context) {

        for (Account account : accounts) {
        account.parentId = parent;
        
        //perform other processing or callout
        
        }
        update accounts;
    }  
}


Add this class as a job on the queue

//find all accounts in ‘NY’
List<Account> accounts = [select id from account where billingstate = ‘NY’];

//find a specific parent account for all records
Id parentId = [select id from account where name = 'ACME Corp'][0].Id;

//instantiate a new instance of the Queueable class
UpdateParentAccount updateJob = new UpdateParentAccount(accounts, parentId);

//enqueue the job for processing
ID jobID = System.enqueueJob(updateJob);

Monitor progress either through the Apex Jobs page or programmatically by querying AsyncApexJob.

SELECT Id, Status, NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID

Test Class:

@isTest
public class UpdateParentAccountTest {

    @testSetup 
    static void setup() {
        List<Account> accounts = new List<Account>();
        // add a parent account
        accounts.add(new Account(name='Parent'));
        // add 100 child accounts
        for (Integer i = 0; i < 100; i++) {
            accounts.add(new Account(
                name='Test Account'+i
                ));
        }
        insert accounts;
    }
    
    static testmethod void testQueueable() {
     //Query for test data to pass to queueable class
     Id parentId = [Select Id From Account Where Name = 'Parent'][0].Id;
     List<Account> accounts = [Select Id, Name From Account Where Name Like 'Test Account%'];
     //Create our Queueable instance
     UpdateParentAccount updater = new UpdateParentAccount(accounts, parentId);
     //Test.startTest() and Test.stopTest() block to force async processes to run
    Test.startTest();        
        System.enqueueJob(updater);
    Test.stopTest();        
     //Validate the job ran. Check if record have correct parentId now
     System.assertEquals(100, [select count() from account where parentId = :parentId]);

    }

}











Validation in flow input text field in sfdc: Maximum 255 characters limit

The input text field validate in sfdc flow behaves opposite of the generic sfdc validation rule.  Here the validation formula is evaluating ...