Add new apex rule ApexUnitTestClassShouldHaveRunAs

This commit is contained in:
Thomas Prouvot 2022-10-11 16:47:16 +02:00
parent c0f88d004d
commit a48b56b5c3
9 changed files with 212 additions and 0 deletions

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ node_modules
# rule docs are generated
docs/pages/pmd/rules
.history/*

Binary file not shown.

View File

@ -0,0 +1,45 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex.rule.bestpractices;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
import net.sourceforge.pmd.lang.apex.ast.ASTRunAsBlockStatement;
import net.sourceforge.pmd.lang.apex.ast.ApexNode;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexUnitTestRule;
/**
* Apex unit tests should have System.runAs methods in them
*
* @author t.prouvot
*/
public class ApexUnitTestClassShouldHaveRunAsRule extends AbstractApexUnitTestRule {
@Override
public Object visit(ASTMethod node, Object data) {
if (!isTestMethodOrClass(node)) {
return data;
}
return checkForRunAsStatements(node, data);
}
private Object checkForRunAsStatements(ApexNode<?> node, Object data) {
final List<ASTBlockStatement> blockStatements = node.findDescendantsOfType(ASTBlockStatement.class);
final List<ASTRunAsBlockStatement> runAsStatements = new ArrayList<>();
for (ASTBlockStatement blockStatement : blockStatements) {
runAsStatements.addAll(blockStatement.findDescendantsOfType(ASTRunAsBlockStatement.class));
}
if (!!runAsStatements.isEmpty()) {
addViolation(data, node);
}
return data;
}
}

View File

@ -64,6 +64,44 @@ public class Foo {
</example>
</rule>
<rule name="ApexUnitTestClassShouldHaveRunAs"
language="apex"
since="6.51.0"
message="Apex unit tests should use System.runAs() method"
class="net.sourceforge.pmd.lang.apex.rule.bestpractices.ApexUnitTestClassShouldHaveRunAsRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_bestpractices.html#apexunittestclassshouldhaverunas">
<description>
Apex unit tests should include at least one runAs method. This makes the tests more robust, and independent from the
user running it.
</description>
<priority>3</priority>
<example>
<![CDATA[
@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());
}
}
}
]]>
</example>
</rule>
<rule name="ApexUnitTestMethodShouldHaveIsTestAnnotation"
since="6.13.0"
language="apex"

View File

@ -9,6 +9,7 @@
</description>
<rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveAsserts" deprecated="true" />
<rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveRunAs" deprecated="true" />
<rule ref="category/apex/bestpractices.xml/ApexUnitTestShouldNotUseSeeAllDataTrue" deprecated="true" />
</ruleset>

View File

@ -250,6 +250,9 @@
<property name="cc_block_highlighting" value="false" />
</properties>
</rule>
<rule ref="category/apex/bestpractices.xml/ApexUnitTestClassShouldHaveRunAs" message="Apex unit test classes should have at least one System.runAs() call">
<priority>3</priority>
</rule>
<!-- <rule ref="category/apex/bestpractices.xml/ApexAssertionsShouldIncludeMessage"/> -->
<!-- <rule ref="category/apex/bestpractices.xml/ApexUnitTestMethodShouldHaveIsTestAnnotation"/> -->
<!-- <rule ref="category/apex/errorprone.xml/TestMethodsMustBeInTestClasses"/> -->

View File

@ -0,0 +1,11 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex.rule.bestpractices;
import net.sourceforge.pmd.testframework.PmdRuleTst;
public class ApexUnitTestClassShouldHaveRunAsTest extends PmdRuleTst {
// no additional unit tests
}

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<test-data xmlns="http://pmd.sourceforge.net/rule-tests" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description>Problematic apex unit test - no runAs calls</description>
<expected-problems>1</expected-problems>
<code>
<![CDATA[
@isTest
private class TestRunAs {
public static testMethod void testNoRunAs() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User u2 = new User(Alias = 'newUser', Email='newuser@testorg.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='newuser@testorg.com');
System.debug('Current User: ' + UserInfo.getUserName());
}
}
]]>
</code>
</test-code>
<test-code>
<description>ApexUnitTestClassShouldHaveRunAs assumes APEX is case sensitive</description>
<expected-problems>0</expected-problems>
<code>
<![CDATA[
@isTest
private class TestRunAs {
@isTest
static void testIgnoreCase() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User usr = new User(Alias = 'newUser', Email='newuser@testorg.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='newuser@testorg.com');
SYSTEM.runAs(usr) {
System.debug('Current User: ' + UserInfo.getUserName());
}
}
}
]]>
</code>
</test-code>
<test-code>
<description>ApexUnitTestClassShouldHaveRunAs normal test case</description>
<expected-problems>0</expected-problems>
<code>
<![CDATA[
@isTest
private class TestRunAs {
public static testMethod void testIgnoreCase() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User usr = new User(Alias = 'newUser', Email='newuser@testorg.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='newuser@testorg.com');
System.runAs(usr) {
System.debug('Current User: ' + UserInfo.getUserName());
}
}
}
]]>
</code>
</test-code>
<test-code>
<description>ApexUnitTestClassShouldHaveRunAs: Verify use of custom class, negative test</description>
<expected-problems>2</expected-problems>
<expected-linenumbers>3,7</expected-linenumbers>
<code>
<![CDATA[
@isTest
public class RunAs {
public static testMethod void testRunAs() {
MyRunAs.runAs(someUser);
}
public static testMethod void testLocalVerify() {
verifyState();
}
private static void verifyState() {
}
}
]]>
</code>
</test-code>
</test-data>

View File

@ -0,0 +1,14 @@
<?xml version="1.0"?>
<ruleset name="6510"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
<description>
This ruleset contains links to rules that are new in PMD v6.51.0
</description>
<rule ref="rulesets/apex/apexunit.xml/ApexUnitTestClassShouldHaveRunAs" />
</ruleset>