Table of Contents
ApexAssertionsShouldIncludeMessage
Since: PMD 6.13.0
Priority: Medium (3)
The second parameter of System.assert/third parameter of System.assertEquals/System.assertNotEquals is a message. Having a second/third parameter provides more information and makes it easier to debug the test failure and improves the readability of test output.
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.ApexAssertionsShouldIncludeMessageRule
Example(s):
@isTest
public class Foo {
@isTest
static void methodATest() {
System.assertNotEquals('123', o.StageName); // not good
System.assertEquals('123', o.StageName, 'Opportunity stageName is wrong.'); // good
System.assert(o.isClosed); // not good
System.assert(o.isClosed, 'Opportunity is not closed.'); // good
}
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/ApexAssertionsShouldIncludeMessage" />
ApexUnitTestClassShouldHaveAsserts
Since: PMD 5.5.1
Priority: Medium (3)
Apex unit tests should include at least one assertion. This makes the tests more robust, and using assert with messages provide the developer a clearer idea of what the test does. Custom assert method invocation patterns can be specified using the ‘additionalAssertMethodPattern’ property if required.
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.ApexUnitTestClassShouldHaveAssertsRule
Example(s):
@isTest
public class Foo {
public static testMethod void testSomething() {
Account a = null;
// This is better than having a NullPointerException
// System.assertNotEquals(a, null, 'account not found');
a.toString();
}
}
This rule has the following properties:
Name | Default Value | Description |
---|---|---|
additionalAssertMethodPattern | A regular expression for one or more custom test assertion method patterns. |
Use this rule with the default properties by just referencing it:
<rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveAsserts" />
Use this rule and customize it:
<rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveAsserts">
<properties>
<property name="additionalAssertMethodPattern" value="" />
</properties>
</rule>
ApexUnitTestClassShouldHaveRunAs
Since: PMD 6.51.0
Priority: Medium (3)
Apex unit tests should include at least one runAs method. This makes the tests more robust, and independent from the user running it.
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.ApexUnitTestClassShouldHaveRunAsRule
Example(s):
@isTest
private class TestRunAs {
public static testMethod void testRunAs() {
// Setup test data
// Create a unique UserName
String uniqueUserName = 'standarduser' + DateTime.now().getTime() + '@testorg.com';
// This code runs as the system user
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User u = new User(Alias = 'standt', Email='standarduser@testorg.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles',
UserName=uniqueUserName);
System.runAs(u) {
// The following code runs as user 'u'
System.debug('Current User: ' + UserInfo.getUserName());
System.debug('Current Profile: ' + UserInfo.getProfileId());
}
}
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveRunAs" />
ApexUnitTestMethodShouldHaveIsTestAnnotation
Since: PMD 6.13.0
Priority: Medium (3)
Apex test methods should have @isTest
annotation instead of the testMethod
keyword,
as testMethod
is deprecated.
Salesforce advices to use @isTest
annotation for test classes and methods.
This rule is defined by the following XPath expression:
//Method[ModifierNode[@DeprecatedTestMethod = true()]]
Example(s):
@isTest
private class ATest {
@isTest
static void methodATest() {
}
static void methodBTest() {
}
@isTest static void methodCTest() {
System.assert(1==2);
}
static testmethod void methodCTest() {
System.debug('I am a debug statement');
}
private void fetchData() {
}
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/ApexUnitTestMethodShouldHaveIsTestAnnotation" />
ApexUnitTestShouldNotUseSeeAllDataTrue
Since: PMD 5.5.1
Priority: Medium (3)
Apex unit tests should not use @isTest(seeAllData=true) because it opens up the existing database data for unexpected modification by tests.
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.ApexUnitTestShouldNotUseSeeAllDataTrueRule
Example(s):
@isTest(seeAllData = true)
public class Foo {
public static testMethod void testSomething() {
Account a = null;
// This is better than having a NullPointerException
// System.assertNotEquals(a, null, 'account not found');
a.toString();
}
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/ApexUnitTestShouldNotUseSeeAllDataTrue" />
AvoidGlobalModifier
Since: PMD 5.5.0
Priority: Medium (3)
Global classes should be avoided (especially in managed packages) as they can never be deleted or changed in signature. Always check twice if something needs to be global. Many interfaces (e.g. Batch) required global modifiers in the past but don’t require this anymore. Don’t lock yourself in.
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.AvoidGlobalModifierRule
Example(s):
global class Unchangeable {
global UndeletableType unchangable(UndeletableType param) {
// ...
}
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/AvoidGlobalModifier" />
AvoidLogicInTrigger
Since: PMD 5.5.0
Priority: Medium (3)
As triggers do not allow methods like regular classes they are less flexible and suited to apply good encapsulation style. Therefore delegate the triggers work to a regular class (often called Trigger handler class).
See more here: https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.AvoidLogicInTriggerRule
Example(s):
trigger Accounts on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
for(Account acc : Trigger.new) {
if(Trigger.isInsert) {
// ...
}
// ...
if(Trigger.isDelete) {
// ...
}
}
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/AvoidLogicInTrigger" />
DebugsShouldUseLoggingLevel
Since: PMD 6.18.0
Priority: Medium (3)
The first parameter of System.debug, when using the signature with two parameters, is a LoggingLevel enum.
Having the Logging Level specified provides a cleaner log, and improves readability of it.
This rule is defined by the following XPath expression:
//MethodCallExpression[lower-case(@FullMethodName)='system.debug'][count(*)=2
or ($strictMode=true() and count(*)=3 and lower-case(VariableExpression/@Image)='debug')]
Example(s):
@isTest
public class Foo {
@isTest
static void bar() {
System.debug('Hey this code executed.'); // not good
System.debug(LoggingLevel.WARN, 'Hey, something might be wrong.'); // good
System.debug(LoggingLevel.DEBUG, 'Hey, something happened.'); // not good when on strict mode
}
}
This rule has the following properties:
Name | Default Value | Description |
---|---|---|
strictMode | false | If true, mark statements that use the DEBUG enum of LoggingLevel. |
Use this rule with the default properties by just referencing it:
<rule ref="category/apex/bestpractices.xml/DebugsShouldUseLoggingLevel" />
Use this rule and customize it:
<rule ref="category/apex/bestpractices.xml/DebugsShouldUseLoggingLevel">
<properties>
<property name="strictMode" value="false" />
</properties>
</rule>
QueueableWithoutFinalizer
Since: PMD 7.8.0
Priority: Low (5)
Detects when the Queueable interface is used but a Finalizer is not attached.
It is best practice to call the System.attachFinalizer(Finalizer f)
method within the execute
method of a class which implements the Queueable
interface.
Without attaching a Finalizer, there is no way of designing error recovery actions should the Queueable action fail.
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.QueueableWithoutFinalizerRule
Example(s):
// Incorrect code, does not attach a finalizer.
public class UserUpdater implements Queueable {
public List<User> usersToUpdate;
public UserUpdater(List<User> usersToUpdate) {
this.usersToUpdate = usersToUpdate;
}
public void execute(QueueableContext context) { // no Finalizer is attached
update usersToUpdate;
}
}
// Proper code, attaches a finalizer.
public class UserUpdater implements Queueable, Finalizer {
public List<User> usersToUpdate;
public UserUpdater(List<User> usersToUpdate) {
this.usersToUpdate = usersToUpdate;
}
public void execute(QueueableContext context) {
System.attachFinalizer(this);
update usersToUpdate;
}
public void execute(FinalizerContext ctx) {
if (ctx.getResult() == ParentJobResult.SUCCESS) {
// Handle success
} else {
// Handle failure
}
}
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/QueueableWithoutFinalizer" />
UnusedLocalVariable
Since: PMD 6.23.0
Priority: Low (5)
Detects when a local variable is declared and/or assigned but not used.
This rule is defined by the following Java class: net.sourceforge.pmd.lang.apex.rule.bestpractices.UnusedLocalVariableRule
Example(s):
public Boolean bar(String z) {
String x = 'some string'; // not used
String y = 'some other string'; // used in the next line
return z.equals(y);
}
Use this rule by referencing it:
<rule ref="category/apex/bestpractices.xml/UnusedLocalVariable" />