063_Apex 的 Test类说明
阅读原文时间:2023年07月08日阅读:1

@isTest
public class TestUtil {
public static void createTestAccounts() {
// Create some test accounts
}
public static void createTestContacts() {
// Create some test contacts
}
}

或者

static testMethod void testName() {
// code_block
}

  @isTest 定义为@isTest的类和方法可以是私有的也可以是公共的。 定义为@isTest的类必须是顶级的

注意 :有时候测试方法需要访问预先存在的数据。要访问组织数据,请使用@isTest注释测试方法(SeeAllData = true)

@testSetup static void methodName() {
}

  @testSetup : creating common test records that are available for all test methods in the class.

1. 测试类

a. 为啥要写烦人的测试类

  1. 当SandBox 部署Code到正式环境时,SF强制要强(>=75%,平台要求)。
  2. 对功能模块检测(单元测试不保证程序做正确的事,但能帮助保证程序正确地做事)。
  3. 反馈速度快,一旦在执行测试类时,通过断言,出现预期结果与实际结果不符合时,就发现问题,比从测试人员反馈即时。
  4. 后期如果对程序修改,比如新加字段,修改字段类型,执行测试类时,可以发现新加的内容是否对原有逻辑造成影响。
  5. 文档作用。(因为测试类根据场景来做的,通过大致阅读测试类,不用看原有代码,可以大概知道对应的功能,前提是测试比效规范和有意义的说明)
  6. 对功能设计的反馈。(如果一个功能很难写出对应的测试类,则该功能的设计存在不良的缺陷)

b. 写测试类面临的问题

  1. 项目时间问题(认为测试类不重要,所以并没有预留出足够的时间用来书写测试类,导致开发人员抱着能部署的心态书写测试类,把目标定在75%这个点上)
  2. 开发人员不重视测试类,以完成功能开发为目地,而不是写出符合要求,且健状的程序来要求自己。

c. SF测试类

  1. 测试类中可直接访问的对象有如下 User,Profile,Organization,AsyncApexJob,CronTrigger,RecordType,ApexClass,ApexTrigger, ApexComponent,ApexPage
  2. 使用IsTest(SeeAllData=true) 可以直接访问系统中的记录
  3. 测试数据与系统数据隔离
  4. 测试类中无法创建字段历史,因为测试数据不会提交(之前遇到过更新记录后,查询历史,发现历史为空)
  5. 为了避免对一个对象的创建在每个测试类中书写,可以创建一个类,专门来创建每个对象,类似于这样。

@isTest
public class TestData {
public static Account getAccount(Id recordTypeId){
Account entity = new Account();
entity.Name = 'TestAccount';
entity.RecordTypeId = recordTypeId;
return entity;
}
public static Account getAccount(String nameIndex){
Account entity = new Account();
entity.Name = 'TestAccount'+nameIndex;
return entity;
}
public static Contact getContact(Id accountId,String nameIndex){
Contact con = new Contact();
con.LastName = 'TestContact'+nameIndex;
con.AccountId = accountId;
return con;
}
}

6 . 需要测试的代码

// 一个小例子
//@Test {UnitClass:[
// testAccountAction_getAccount(),
// testAccountAction_getContact()
// ]}
//@See {}
//@Schedule{}
//@Modify[
// {时间:2016年8月29日 00:18,修改人:在山的那边 ,描述:init}
//]
//
public class AccountAction {
@TestVisible private Account account;

public void getAccount(){
this.account = [SELECT Id,Name FROM Account][0];
}

public List getContact(){
List conList = [SELECT Id,Name FROM Contact WHERE AccountId =:account.Id];
return conList;
}

}

7 . 创建测试类 SF创建测试类很简单,在类前加上annotation @isTest 或者 在使用关键字 testMethod 和 static 修饰方法(如下形式),个人偏向于测试方法写在一个测试类中,当测试类较多时,另起一个测试文件,而不是一个class写一个测试类文件

public class myClass {
static testMethod void myTest() {
// Add test method logic using System.assert(), System.assertEquals()
// and System.assertNotEquals() here.
}
}
@isTest
private class MyTest {
// Methods for testing
}
@isTest
public class UnitClass {

@testSetup static void methodName() {
Account acc01 = TestData.getAccount('01');
Insert acc01;

Contact con01 = TestData.getContact(acc01.Id, '01');  
Insert con01;  

}

//个习惯测试类的命名格式为:test+类名+"_"+方法名,在注释中同样写清楚测试类怀测试方法
//

@isTest static void testAccountAction_getAccount() {
AccountAction accAction = new AccountAction();
accAction.getAccount();
System.assertEquals('TestAccount01', accAction.account.Name);
}

@isTest static void testAccountAction_getContact(){
AccountAction accAction = new AccountAction();
accAction.getAccount();
List conList = accAction.getContact();
System.assertEquals('TestContact01', conList.get(0).Name);
}
}

代码中的注释为多行 ,排版问题改为//
在sublime中通过shift + 双击可以导航到定义处,这就是为什么在注释中写明测试类与测试的方法
这样在程序中可以点击导航对应的测试方法,在测试方法中能快速导航到程序中

8 . 在控制台执行对应的测试类。

9 . @TestVisible 作用是访问类的私有变量,如一些内部类或者私有变量需要访问或者给值时

10 . @testSetup 在执行测试方法前执行,类似于junit中的@before 可以执行一些公共数据的新建等工作,但是一但该方法有错误,则整个测试类全部失败,建议只有一个testsetup方法

11 . 通过System.assertEquals or System.assert() or System.assertNotEquals() 来验证预期结果与实际结果 比较,一旦不成立,则测试类提示失败,日志中会体现预期值为多少,实际为多少。 

12 . runAs 模拟不同用户操作

public static testMethod void testBatch() {
user u = [SELECT ID, UserName FROM User
WHERE username='testuser1@acme.com'];
user u2 = [SELECT ID, UserName FROM User
WHERE username='testuser2@acme.com'];
String u2id = u2.id;
// Create 200 test accounts - this simulates one execute.
// Important - the Salesforce.com test framework only allows you to
// test one execute.
List accns = new List();
for(integer i = 0; i<200; i++){
Account a = new Account(Name='testAccount'+'i',
Ownerid = u.ID);
accns.add(a);
}
insert accns;
Test.StartTest();
OwnerReassignment reassign = new OwnerReassignment();
reassign.query='SELECT ID, Name, Ownerid ' +
'FROM Account ' +
'WHERE OwnerId=\'' + u.Id + '\'' +
' LIMIT 200';
reassign.email='admin@acme.com';
reassign.fromUserId = u.Id;
reassign.toUserId = u2.Id;
ID batchprocessid = Database.executeBatch(reassign);
Test.StopTest();
System.AssertEquals(
database.countquery('SELECT COUNT()'
+' FROM Account WHERE OwnerId=\'' + u2.Id + '\''),
200);
}
}

13 . startTest 和 stopTest 在这两个方法中间执行一些耗时操作,在stoptest 后再使用断言判断,如job,如果不在方法中间,则断言取不到值,原因是当执行判断时,job也许还没有执行完成。同时还能避免一些limit问题,webservice,remote acton 操作时都需要写在中间。该测试方法中只能调用一次。

14 . 测试方法中不要出现硬码,否则出现在Sandbox中正常,到正式中就出错,少依赖基础数据。

15 . Trigger 覆盖率必须>0

16 . try…catch 捕获代码中出现的异常,如trigger中 字段.adderror 等形为

以上仅参考,如果错误欢请指出,参考内容为SF的apex 指南, SF也建议不要将目光仅放在75%上,要尽量达到95%以上,最后需要通过断言判断程序是否与期望相同

本文转自 :https://my.oschina.net/SpringZhang/blog/739064

***************

I will recommend you to start using trailhead to learn about test classes
1) https://trailhead.salesforce.com/modules/apex_testing

Also please check below post
1) https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_qs_test.htm
2) https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_testing_example.htm

sample Test classes
1) http://amitsalesforce.blogspot.com/2015/06/best-practice-for-test-classes-sample.html

Please follow below salesforce Best Practice for Test Classes :-

1. Test class must start with @isTest annotation if class class version is more than 25
2. Test environment support @testVisible , @testSetUp as well
3. Unit test is to test particular piece of code working properly or not .
4. Unit test method takes no argument ,commit no data to database ,send no email ,flagged with testMethod keyword .
5. To deploy to production at-least 75% code coverage is required
6. System.debug statement are not counted as a part of apex code limit.
7. Test method and test classes are not counted as a part of code limit
9. We should not focus on the  percentage of code coverage ,we should make sure that every use case should covered including positive, negative,bulk and single record .
Single Action -To verify that the the single record produces the correct an expected result .
Bulk action -Any apex record trigger ,class or extension must be invoked for 1-200 records .
Positive behavior : Test every expected behavior occurs through every expected permutation , i,e user filled out every correctly data and not go past the limit .
Negative Testcase :-Not to add future date , Not to specify negative amount.
Restricted User :-Test whether a user with restricted access used in your code .
10. Test class should be annotated with @isTest .
11 . @isTest annotation with test method  is equivalent to testMethod keyword .
12. Test method should static and no void return type .
13. Test class and method default access is private ,no matter to add access specifier .
14. classes with @isTest annotation can't be a interface or enum .
15. Test method code can't be invoked by non test request .
16. Stating with salesforce API 28.0 test method can not reside inside non test classes .
17. @Testvisible annotation to make visible private methods inside test classes.
18. Test method can not be used to test web-service call out . Please use call out mock .
19. You can't  send email from test method.
20.User, profile, organization, AsyncApexjob, Corntrigger, RecordType, ApexClass, ApexComponent ,ApexPage we can access without (seeAllData=true) .
21. SeeAllData=true will not work for API 23 version eailer .
22. Accessing static resource test records in test class e,g List accList=Test.loadData(Account,SobjectType,'ResourceName').
23. Create TestFactory class with @isTest annotation to exclude from organization code size limit .
24. @testSetup to create test records once in a method  and use in every test method in the test class .
25. We can run unit test by using Salesforce Standard UI,Force.com IDE ,Console ,API.
26. Maximum number of test classes run per 24 hour of period is  not grater of 500 or 10 multiplication of test classes of your organization.
27. As apex runs in system mode so the permission and record sharing are not taken into account . So we need to use system.runAs to enforce record sharing .
28. System.runAs will not enforce user permission or field level permission .
29. Every test to runAs count against the total number of DML issued in the process .