Concepts or coding lessons of Salesforce that you can implement easily

Salesforce Interview Questions - Part 6


121. What are the Trigger Best Practices?
Answer :
Best Practice #1: One Trigger Per Object
A single Apex Trigger is all you need for one particular object. If you develop multiple Triggers for a single object, you have no way of controlling the order of execution if those Triggers can run in the same contexts. Many times, the order of execution doesn’t matter but when it does matter, it’s nearly impossible to maintain proper flow control. A single Trigger can handle all possible combinations of Trigger contexts which are:

  • before insert
  • after insert
  • before update
  • after update
  • before delete
  • after delete
  • after undelete

So as a best practice, create one Trigger per object and let it handle all of the contexts that you need. Here is an example of a Trigger that implements all possible contexts:

trigger OpportunityTrigger on Opportunity (
  before insert, before update, before delete, 
  after insert, after update, after delete, after undelete) {

  // trigger body

}


Best Practice #2: Bulkify your Helper Methods
Make sure any code that runs a query or DML operation does it in a bulk manner and doesn't execute within an iteration or a for loop. Executing queries or DML operations within an iteration adds risk that the governor limits will be exceeded. This is also true for any helper or utility methods an Apex request executes.
Governor limits are calculated at runtime. After the request is initiated (Trigger, Visualforce page, etc.), any Apex code executed in that transaction applies and shares the governor limits. So if a trigger uses some Apex methods written in a helper class, it's important that those shared Apex methods are properly designed to handle bulk records. These methods should be written to be invoked with a set of records, especially if the method has a SOQL query or DML operation.
For example, if the Apex method performs a SOQL query, that method should receive a collection (Array, List, Set, etc.) of records so when it performs the query, it can perform the query for all records in the Apex transaction. Otherwise, if the Apex method is called individually for each record being processed, the Apex transaction will inefficiently run queries and possibly exceed the allowed number of queries allowed in that transaction. The same is true for DML statements in Apex methods.
So please make sure any utility or helper methods are efficiently written to handle collections of records. This will avoid unnecessarily executing inefficient queries and DML operations.
Best Practice #3: Logic-less Triggers
Another widely-recognized best practice is to make your Triggers logic-less. That means, the role of the Trigger is just to delegate the logic responsibilities to some other handler class. There are many reasons to do this. For one, testing a Trigger is difficult if all of the application logic is in the trigger itself. If you write methods in your Triggers, those can’t be exposed for test purposes. You also can’t expose logic to be re-used anywhere else in your org. 
Good old OO principles tell us that this is a bad practice. And to top it all off, cramming all of your logic into a Trigger is going to make for a mess one day. To remedy this scenario, just create a handler class and let your Trigger delegate to it. Here is an example:
trigger OpportunityTrigger on Opportunity (after insert) {
OpportunityTriggerHandler.handleAfterInsert(Trigger.new);
}
And the handler class:

public class OpportunityTriggerHandler {

  public static void handleAfterInsert(List opps) {
    // handler logic
  }
}

Best Practice #4: Avoid SOQL Queries or DML statements inside FOR Loops
A common mistake is that queries or DML statements are placed inside a for loop. There is a governor limit that enforces a maximum number of SOQL queries. There is another that enforces a maximum number of DML statements (insert, update, delete, undelete). When these operations are placed inside a for loop, database operations are invoked once per iteration of the loop making it very easy to reach these governor limits.
Instead, move any database operations outside of for loops. If you need to query, query once, retrieve all the necessary data in a single query, then iterate over the results. If you need to modify the data, batch up data into a list and invoke your DML once on that list of data.

Best Practice #5: Using Collections, Streamlining Queries, and Efficient For Loops
It is important to use Apex Collections to efficiently query data and store the data in memory. A combination of using collections and streamlining SOQL queries can substantially help writing efficient Apex code and avoid governor limits.

Best Practice #6: Querying Large Data Sets
The total number of records that can be returned by SOQL queries in a request is 50,000. If returning a large set of queries causes you to exceed your heap limit, then a SOQL query for loop must be used instead. It can process multiple batches of records through the use of internal calls to query and queryMore.

For example, if the results are too large, the syntax below causes a runtime exception:
//A runtime exception is thrown if this query returns enough records to exceed your heap limit.
Account[] accts = [SELECT id FROM account];

Instead, use a SOQL query for loop as in one of the following examples:

// Use this format for efficiency if you are executing DML statements 
// within the for loop.  Be careful not to exceed the 150 DML statement limit.

Account[] accts = new Account[];

for (List<Account> acct&nbsp;: [SELECT id, name FROM account
                            WHERE name LIKE 'Acme']) {
    // Your logic here
    accts.add(acct);
}

update accts;

Let the Force.com platform chunk your large query results into batches of 200 records by using this syntax where the SOQL query is in the for loop definition, and then handle the individual datasets in the for loop logic.

Best Practice #7: Use of the Limits Apex Methods to Avoid Hitting Governor Limits
Apex has a System class called Limits that lets you output debug messages for each governor limit. There are two versions of every method: the first returns the amount of the resource that has been used in the current context, while the second version contains the word limit and returns the total amount of the resource that is available for that context.


122. What are Apex Unit Tests?
Answer: 
To facilitate the development of robust, error-free code, Apex supports the creation and execution of unit tests. Unit tests are class methods that verify whether a particular piece of code is working properly. Unit test methods take no arguments, commit no data to the database, send no emails, and are flagged with the testMethod keyword or the isTest annotation in the method definition. Also, test methods must be defined in test classes, that is, classes annotated with isTest.
For example:
@isTest
private class myClass {
     static testMethod void myTest() {
        // code_block
    }
}

This is the same test class as in the previous example but it defines the test method with the isTest annotation instead.
@isTest
private class myClass {
    @isTest static void myTest() {
        // code_block
    }
}

123. What are the Unit Test Considerations ?
Answer :
Here are some things to note about unit tests.


  • Starting with Salesforce API 28.0, test methods can no longer reside in non-test classes and must be part of classes annotated with isTest. See the TestVisible annotation to learn how you can access private class members from a test class.
  • Test methods can’t be used to test Web service callouts. Instead, use mock callouts. See Test Web Service Callouts and Testing HTTP Callouts.
  • You can’t send email messages from a test method.
  • Since test methods don’t commit data created in the test, you don’t have to delete test data upon completion.
  • If a test class contains a static member variable, and the variable’s value is changed in a testSetup or test method, the new value isn’t preserved. Other test methods in this class get the original value of the static member variable. This behavior also applies when the static member variable is defined in another class and accessed in test methods.
  • For some sObjects that have fields with unique constraints, inserting duplicate sObject records results in an error. For example, inserting CollaborationGroup sObjects with the same names results in an error because CollaborationGroup records must have unique names.
  • Tracked changes for a record (FeedTrackedChange records) in Chatter feeds aren't available when test methods modify the associated record. FeedTrackedChange records require the change to the parent record they're associated with to be committed to the database before they're created. Since test methods don't commit data, they don't result in the creation of FeedTrackedChange records. Similarly, field history tracking records (such as AccountHistory) can't be created in test methods because they require other sObject records to be committed first (for example, Account).

124. How do you unit test a trigger when you don’t know the required fields?
Answer :
Customers can have validation on custom fields via validation rules and triggers, so handling that in your unit tests without customer intervention is next to impossible. The first step to reducing issues is to have your test data populate all standard fields and ensure the data uses the most common formatting for your customer base (US style phone numbers and addresses for the US for example).

Beyond that you can use the new Reflection features added to Salesforce in Summer ’12 to allow customers to create unit test data classes that can be used by your managed package. Basically you define a test data generation interface and the customer creates an Apex class to generate data for you. Here’s an example of using Reflection in a similar manner on the DeveloperForce blog:http://blogs.developerforce.com/developer-relations/2012/05/dynamic-apex-class-instantiation-in-summer-12.html

Using the method for unit tests run on install might be problematic as you’d have to have the customer create the class before they install your package and your package could only look for the class by name (or iterate through all default namespace classes and check for the correct interface). However, it’s no longer necessary for unit tests to run during installation for managed packages and by default they do not.

The Reflection method requires some coding knowledge on the customer side, but you could add a tool in your application to generate the custom unit test data class for the customer.

FYI, it’s no longer necessary for managed package unit tests to succeed in customer orgs. They’re not required on install, they will no longer prevent deployment to production and they don’t count as part of the customers unit test coverage percentage for purposes of deployment. The only exception to that is if the customer uses ANT and sets the runAllTests parameter to true.

125. How do you write a unit test for a trigger whose only function is to make a callout?
Answer :
Both future methods and callouts can be unit tested.

To test future methods simply make your call to any future method between Test.startTest();and Test.stopTest(); statements and the future method will return when Test.stopTest(); is called. See the documentation for the Test class here: System.Test

Testing callouts is a bit trickier though. Basically in your callout code you check to see if you’re executing within a unit test context by checking Test.isRunningTest() and instead of getting your callout response from an HttpResponse.send() request, you return a pre-built test string instead. There’s one example of this method here: http://www.iterativelogic.com/unit-test-callouts-in-apex-code-part-2/


There’s also an older example of callout unit testing that uses a static variable you set in your unit test. Just replace that static variable with a call to Test.isRunningTest() and their example works fairly well as well. That example can be found here:http://sfdc.arrowpointe.com/2009/05/01/testing-http-callouts/

126. Can I find out if the current user has access to a record without querying?
Answer :
To find out if a particular user has Edit access to a record, use the UserRecordAccess object. This object is available in API version 24.0 and later. You can use SOQL to query this object to find out if the user has edit access to the record in question.

SELECT RecordId, HasEditAccess FROM UserRecordAccess WHERE UserId = [single ID] AND RecordId = [single ID]

If you want to check a batch of records you can use

SELECT RecordId FROM UserRecordAccess WHERE UserId=:UserInfo.getUserId() AND HasReadAccess = true ANDRecordId IN :allRecordIds LIMIT 200

But make sure that allRecordIds is a LIST of IDs. It doesn’t work if allRecordIds is a SET of IDs. I guess that’s a bug.


Also, only a maximum amount of 200 recordIds can be checked in one query.


122. What are Apex Unit Tests?
Answer: 
To facilitate the development of robust, error-free code, Apex supports the creation and execution of unit tests. Unit tests are class methods that verify whether a particular piece of code is working properly. Unit test methods take no arguments, commit no data to the database, send no emails, and are flagged with the testMethod keyword or the isTest annotation in the method definition. Also, test methods must be defined in test classes, that is, classes annotated with isTest.
For example:
@isTest
private class myClass {
     static testMethod void myTest() {
        // code_block
    }
}

This is the same test class as in the previous example but it defines the test method with the isTest annotation instead.
@isTest
private class myClass {
    @isTest static void myTest() {
        // code_block
    }
}

123. What are the Unit Test Considerations ?
Answer :
Here are some things to note about unit tests.


  • Starting with Salesforce API 28.0, test methods can no longer reside in non-test classes and must be part of classes annotated with isTest. See the TestVisible annotation to learn how you can access private class members from a test class.
  • Test methods can’t be used to test Web service callouts. Instead, use mock callouts. See Test Web Service Callouts and Testing HTTP Callouts.
  • You can’t send email messages from a test method.
  • Since test methods don’t commit data created in the test, you don’t have to delete test data upon completion.
  • If a test class contains a static member variable, and the variable’s value is changed in a testSetup or test method, the new value isn’t preserved. Other test methods in this class get the original value of the static member variable. This behavior also applies when the static member variable is defined in another class and accessed in test methods.
  • For some sObjects that have fields with unique constraints, inserting duplicate sObject records results in an error. For example, inserting CollaborationGroup sObjects with the same names results in an error because CollaborationGroup records must have unique names.
  • Tracked changes for a record (FeedTrackedChange records) in Chatter feeds aren't available when test methods modify the associated record. FeedTrackedChange records require the change to the parent record they're associated with to be committed to the database before they're created. Since test methods don't commit data, they don't result in the creation of FeedTrackedChange records. Similarly, field history tracking records (such as AccountHistory) can't be created in test methods because they require other sObject records to be committed first (for example, Account).

124. How do you unit test a trigger when you don’t know the required fields?
Answer :
Customers can have validation on custom fields via validation rules and triggers, so handling that in your unit tests without customer intervention is next to impossible. The first step to reducing issues is to have your test data populate all standard fields and ensure the data uses the most common formatting for your customer base (US style phone numbers and addresses for the US for example).

Beyond that you can use the new Reflection features added to Salesforce in Summer ’12 to allow customers to create unit test data classes that can be used by your managed package. Basically you define a test data generation interface and the customer creates an Apex class to generate data for you. Here’s an example of using Reflection in a similar manner on the DeveloperForce blog:http://blogs.developerforce.com/developer-relations/2012/05/dynamic-apex-class-instantiation-in-summer-12.html

Using the method for unit tests run on install might be problematic as you’d have to have the customer create the class before they install your package and your package could only look for the class by name (or iterate through all default namespace classes and check for the correct interface). However, it’s no longer necessary for unit tests to run during installation for managed packages and by default they do not.

The Reflection method requires some coding knowledge on the customer side, but you could add a tool in your application to generate the custom unit test data class for the customer.

FYI, it’s no longer necessary for managed package unit tests to succeed in customer orgs. They’re not required on install, they will no longer prevent deployment to production and they don’t count as part of the customers unit test coverage percentage for purposes of deployment. The only exception to that is if the customer uses ANT and sets the runAllTests parameter to true.

125. How do you write a unit test for a trigger whose only function is to make a callout?
Answer :
Both future methods and callouts can be unit tested.

To test future methods simply make your call to any future method between Test.startTest();and Test.stopTest(); statements and the future method will return when Test.stopTest(); is called. See the documentation for the Test class here: System.Test

Testing callouts is a bit trickier though. Basically in your callout code you check to see if you’re executing within a unit test context by checking Test.isRunningTest() and instead of getting your callout response from an HttpResponse.send() request, you return a pre-built test string instead. There’s one example of this method here: http://www.iterativelogic.com/unit-test-callouts-in-apex-code-part-2/


There’s also an older example of callout unit testing that uses a static variable you set in your unit test. Just replace that static variable with a call to Test.isRunningTest() and their example works fairly well as well. That example can be found here:http://sfdc.arrowpointe.com/2009/05/01/testing-http-callouts/

126. Can I find out if the current user has access to a record without querying?
Answer :
To find out if a particular user has Edit access to a record, use the UserRecordAccess object. This object is available in API version 24.0 and later. You can use SOQL to query this object to find out if the user has edit access to the record in question.

SELECT RecordId, HasEditAccess FROM UserRecordAccess WHERE UserId = [single ID] AND RecordId = [single ID]

If you want to check a batch of records you can use

SELECT RecordId FROM UserRecordAccess WHERE UserId=:UserInfo.getUserId() AND HasReadAccess = true ANDRecordId IN :allRecordIds LIMIT 200

But make sure that allRecordIds is a LIST of IDs. It doesn’t work if allRecordIds is a SET of IDs. I guess that’s a bug.


Also, only a maximum amount of 200 recordIds can be checked in one query.


More Salesforce Interview Questions and Answers:


loading...

No comments:

Post a Comment