What to Test In Apex?
Salesforce.com recommends the following components need to test.
1. Single Records:
1. Single Records:
This includes testing to verify that a single record produces the correct,
expected result
expected result
2. Bulk Records:
Any apex code, whether a triggers, a class or on extension may be used
for 1to 200 records we must test not only the single record case, but the bulk
cases as well.
3. Positive scenarios:
This type of component testing expect a system to save a record without error.
4. Negative scenarios:
This type of component testing expect a system to give error.
5. Restricted User:
Test whether a user with restricted access to the objects used in code sees
the expected behavior, i.e whether they can run the code or receive error
messages.
How is a test method defined?
messages.
How is a test method defined?
A test method is defined as mentioned below:-
Syntax:
static testMethod void testMethodName(){….. Code here ……..}
How is code coverage calculated?
Code coverage percentage is a calculation of the number of covered lines divided
by the sum of the number of covered lines and uncovered lines.
Note: Comments blank lines,System.debug() statements and curly brackets are
excluded
Multiple statements on one line are counted as one line for the purpose of code
coverage.
Which classes are excluded from code coverage calculation?
Test classes (classes that are annotated with @isTest) are excluded from the code
coverage calculation.
Where the code coverage is stored?
Code coverage is stored in two Lightning Platform Tooling API objects:
ApexCodeCoverageAggregate:
It stores the sum of covered lines for a class after checking all test methods that
It stores the sum of covered lines for a class after checking all test methods that
test it
ApexCodeCoverage:
Stores the lines that are covered and uncovered by each individual test method.
Stores the lines that are covered and uncovered by each individual test method.
How to retrieve code coverage information?
We can query these objects by using SOQL and the Tooling API to retrieve
coverage information. Using SOQL queries with Tooling API is an alternative way
of checking code coverage and a quick way to get more detail.
Code coverage best practice?
Some of the best practices are:
Code coverage should not depend on the existing data in the org, i.e. sellAllData
should not be true
For testing trigger and batch class we should do bulk testing with at least 200
records.
records.
Testing should be done for the entire scenario not only for the code coverage
Why code coverage differs between sandbox and production?
Sandbox and production environments often don’t contain the same data and
metadata, so the code coverage results don’t always match.
@isTest annotation ?
Use the @isTest annotation to define classes and methods that only contain code
used for testing our application.
SeeAllData=true annotation ?
Use the @isTest(SeeAllData=true) annotation to grant test classes and individual
test methods access to all data in the organization.
Considerations for the @IsTest(SeeAllData=true) Annotation?
If a test class is defined with the isTest(SeeAllData=true) annotation, this
annotation applies to all its test methods whether the test methods are defined
with the @isTest annotation or the test method keyword.
The isTest(SeeAllData=true) annotation is used to open up data access when
applied at the class or method level. However, using isTest(SeeAllData=false) on
a method doesn’t restrict organization data access for that method if the
containing class has already been defined with the isTest(SeeAllData=true)
annotation. In this case, the method will still have access to all the data in the
organization.
OnInstall = true notation?
Use the @IsTest(OnInstall=true) annotation to specify which Apex tests are
executed during package installation. This annotation is used for tests in
managed or unmanaged packages.
(isParallel=true)?
Use the @isTest(isParallel=true) annotation to indicate test classes that can run
in parallel. Default limits on the number of concurrent tests do not apply to these
test classes.
Can we use (SeeAllData=true) and (isParallel=true) in same apex test method?
@isTest(SeeAllData=true) and @isTest(isParallel=true) annotations cannot be
used together on the same Apex test method.
Which Objects can we access without using seeAllData=true?
We use seeAllData = true to get real-time data in test class, but without using
this also we can get the data from following objects.
User, profile, organization, AsyncApexjob, Corntrigger, RecordType, ApexClass,
ApexComponent , ApexPage and custom metadata types.
Why it is recommended to avoid using seeAllData=true?
Enabling this seeAllData = true exposes the data from the database to the test
class. It is recommended not to use as the code coverage of we apex class or
trigger will now be dependent on the data which is present in org and depending
upon that the code coverage may change
Does Salesforce count calls to system.debug() against the code coverage?
No, Salesforce does not count it against the code coverage.
Why to create separate class for testing purpose?
Advantage of creating a separate class for testing as opposed to adding test
methods to an existing class is that classes defined with isTest don’t count against
our organization limit of 6 MB for all Apex code.
What are the considerations of using isTest annotation?
- Classes and methods defined as isTest can be either private or public.
- Classes defined as isTest must be top-level classes.
- One advantage to creating a separate class for testing is that classes defined with isTest don’t count against our organization limit of 6 MB for all Apex code.
- We can also add the @isTest annotation to individual methods
- Classes defined as isTest can’t be interfaces or enums
- Methods of a 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.
- Test methods can’t be used to test Web service callouts. Instead, use mock callouts
- We can’t send email messages from a test method
- 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.
@testSetup annotation?
Methods that are annotated with @testSetup are used to create test records once
and then access them in every test method in the test class.
Test setup methods enable us to create common test data easily and efficiently.
By setting up records once for the class, we don’t need to re-create records for each test method.
Example: For example, we have a test class, It has two test methods and each
test method required 5 account records.So without creating 5 records for each
test method, we will create a new method with annotation @testSetup then
create only 5 account records. These records can access all test methods using
SOQL query in that test class.
What are the things to remember when we use @testSetup method?
All database changes are rolled back at the end of a test. We can’t use this method on records that existed before the test executed. We also can’t use setCreatedDate in methods annotated with @isTest(SeeAllData=true), because those methods have access to all data in the org. The both parameters (Id recordId, Datetime createdDatetime) of this method are mandatory.
What is the difference between testMethod and @isTest?
@isTest annotation is used to define the test classes which contains code to test
our application and these classes does not count against our overall code
coverage.
testmethod keyword is used to define apex test methods. Also test methods can
be defined in any apex class.
@testVisible annotation?
Some methods are declared as private so we won’t be able to call them outside
the class. However, sometimes we really want to be able to invoke it from a unit
test method.
To resolve this, we can mark the method with a @TestVisible annotation. Then
although it is still private, it is invokable from our unit test methods.
How is a class defined as a test class ?
Use @isTest annotation to define a test class.
What is the use of System.runAs() method?
All Apex code runs in system mode, where the permissions and record sharing of
the current user are not taken into account. The system method runAs enables
us to write test methods that change the user context to an existing user or a
new user so that the user’s record sharing is enforced. The runAs method doesn’t
enforce user permissions or field-level permissions, only record sharing.
The following items use the permissions granted by the user specified with runAs
running as a specific user:
Dynamic Apex Methods using with sharing or without sharing
Shared records
Shared records
The original permissions are reset after runAs completes.The runAs method
ignores user license limits.
Can we use system.run as in all the methods?
System.runAs() must be used only in a test method
Can runAs help in solving mixed DML error?
We can also use the runAs method to perform mixed DML operations in our test
by enclosing the DML operations within the runAs block. In this way, we bypass
the mixed DML error that is otherwise returned when inserting or updating setup
objects together with other sObjects. The moment we do System.Runas(User u),
all the permissions of the user u are re-read form the database and re-applied to
the running context
What is Test.isRunningTest() method?
The Test.isRunningTest() method is used to identify, if the piece of code being
executed is invoked from a Test class execution or from other artefacts such as a
Trigger, Batch Job etc. Returns true if the code being executed is invoked from a
test class otherwise returns a false.
Example:
Performing web service callouts in Apex are not supported within Test
Performing web service callouts in Apex are not supported within Test
Code. Hence we could use the Test.isRunningTest() to conditionally identify and
route the execution of a code block that calls the Test Mock framework to simulate
a mock, callout response.
Use Case of Test.isRunningTest() method
When we are setting up test data from Apex test method, we need a way to
disable the triggers that will fire. It might cause “LimitException: “Too many SOQL
queries: 101″. In this case, the triggers are not the target of the test case, hence
this scenario will cause the test method to fail. It is not necessary to disable the
trigger for every test case, instead we can use isRunningTest().
Setup up the trigger by leveraging isRunningTest(). isRunningTest() – Returns true
if the currently executing code was called by code contained in a test method,
false otherwise. Use this method if we need to run different code depending on
whether it was being called from a test
Other Usage scenarios
1. To ensure the trigger doesn’t execute the batch if Test.IsRunningTest() is true,
and then test the batch class with it’s own test method.
2. Testing callouts – in our callout code we check to see if we‘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.
What is the use of System.Assert/System.AssertEquals Methods?
These methods are used to ensure that the Apex code executes and returns the
expected value.
System.Assert: It accepts two parameter: First one (mandatory) is the condition
test and the second one is used to display a message in case the condition fails.
Syntax: System.assert(var1 == var2,”msg”)
System.AssertEquals: It accepts three parameters; the first two (mandatory) are
the variables that will be tested for equality or inequality, and the third (optional)
one is used to display a message in case the condition fails.
Syntax: System.assertEquals(var1, var2,”msg”);
What is the use of Test.startTest/Test.stopTest method?
Test.startTest and Test.stopTest are used for asynchronous apex, like Batch Apex
and Future calls. Calling method(s) between Test.startTest and Test.stopTest
ensure that any asynchronous transactions finish executing before Test.stopTest() exits.
startTest()
Marks the point in our test code when our test actually begins. Use this method
when we are testing governor limits.
Usage
We can also use this method with stopTest to ensure that all asynchronous calls
that come after the startTest method are run before doing any assertions or
testing. Each test method is allowed to call this method only once.
stopTest()
Marks the point in our test code when our test ends. Use this method in
conjunction with the startTest method.
Usage
Each test method is allowed to call this method only once. Any code that executes
after the stopTest method is assigned the original limits that were in effect before
startTest was called.
Example: if our class makes 98 SOQL queries before it calls startTest, and the
first significant statement after startTest is a DML statement, the program can
now make an additional 100 queries. Once stopTest is called, however, the
program goes back into the original context, and can only make 2 additional
SOQL queries before reaching the limit of 100
Why would a developer use Test.startTest() and Test.stopTest()?
1. To avoid Apex code coverage requirements for the code between these lines.
2. To start and stop anonymous block execution when executing anonymous Apex
code
3. To indicate test code so that it does not impact Apex line count governor limits
4. To create an additional set of governor limits during the execution of a single
test class
Test.setCreatedDate?
Set the Created date field value is used to test records in Salesforce test classes
using setCreatedDate(Id recordId, Datetime createdDatetime) method.
What are considerations while using
setCreatedDate?
All database changes are rolled back at the end of a test. We can’t use this
method on records that existed before the test executed.
We also can’t use setCreatedDate in methods annotated with
@isTest(SeeAllData=true), because those methods have access to all data in the
org. The both parameters (Id recordId, Datetime createdDatetime) of this method are
mandatory.
How to test asynchronous callout?
Because Apex tests don’t support making callouts, we can simulate callout
requests and responses. When we are simulating a callout, the request doesn’t
get sent to the external service, and a mock response is used.
To simulate callouts in continuations, call these methods of the Test class:
Test.setContinuationResponse sets a mock response, and
Test.invokeContinuationMethod causes the callback method for the continuation
to be executed.
How to test a Web Service Callouts?
By default, test methods don’t support web service callouts, and tests that
perform web service callouts fail. To prevent tests from failing and to increase
code coverage, Apex provides the built-in WebServiceMockinterface and the
Test.setMock method.
When we create an Apex class from a WSDL, the methods in the auto-generated
class call WebServiceCallout.invoke, which performs the callout to the external
service. When testing these methods, we can instruct the Apex runtime to
generate a fake response whenever WebServiceCallout.invoke is called. To do so,
implement the WebServiceMock interface and specify a fake response for the Apex
runtime to send
How many types of Assert Statements are there and what is their purpose?
Assert statements are used to compare expected value with the actual value.
There are three types of assert statements :
assertEquals(expVal, actVal); returns true if expVal Matches actVal.
assertNotEqual(expVal, actVal); returns true if expVal does not match actVal.
assertEquals(expVal > actVal); returns true if the condition is satisfied.
Can we populate history tables from unit testing?
We can’t populate the history tables from unit tests as this happens after a
transaction is committed to the database, which doesn’t happen in the test
context, rather the entire transaction is rolled back at the end of the test
How to test future method?
To test future methods make our call to any future method between
Test.startTest(); and Test.stopTest(); statements and the future method will
return when Test.stopTest(); is called.
What is a good practice of testing Batch class?
We should always test batch class with good amount of data
(minimum 200 records) in our test class.
Use Test.startTest() and Test.stopTest() to test batchable classes
When testing can i use existing data?
By design, test classes do not have access to our org’s data unless we explicitly set SeeAllData=true
- We have no way of guaranteeing the data we retrieve will accurately run
- We have no way of guaranteeing the data we expect will exist through we tests.
By setting up we own test data we :
- We remove problems with locks
- Know exactly what is present with regards to good and bad data
- Can help improve our testing by having proper edge cases tested
- Remove dependencies outside of our control
How to test class for batch apex making http apex callouts?
We should be able to do this using HttpCalloutMock and Test.startTest/stopTest.
What are the testing best practices?
What are the testing best practices?
References
http://www.sfdcstuff.com/2017/03/different-ways-of-testing-http-callout.html