Apex基础

Apex 语言亮点

像其他面向对象的编程语言一样,这些是Apex支持的一些语言结构:

  • 类,接口,属性和集合(包括数组)。
  • 对象和数组表示法。
  • 表达式,变量和常量。
  • 条件语句(if-then-else)和控制流语句(for循环和while循环)。

与其他面向对象的编程语言不同,Apex支持:

  • 作为Apex的云开发是在云中存储,编译和执行的。
  • 触发器,类似于数据库系统中的触发器。
  • 数据库语句,允许您直接进行数据库调用和查询语言来查询和搜索数据。
  • 事务和回滚。
  • 全局访问修饰符,它比public修饰符更宽松,并允许跨命名空间和应用程序访问。
  • 自定义代码的版本。

另外,Apex是一个不区分大小写的语言。

Apex语法

  • Switch

    String waterLevel = 'empty';
    //option 1 using a single value
    switch on waterLevel{when 'empty'{System.debug('Fill the tea kettle');}when 'half'{System.debug('Fill the tea kettle');}when 'full'{System.debug('The tea kettle is full');}when else{System.debug('Error!');}
    }
    //option 2 using multiple values
    switch on waterLevel{when 'empty', 'half'{ //when waterLevel is either empty or halfSystem.debug('Fill the tea kettle');}when 'full'{System.debug('The tea kettle is full');}when else{System.debug('Error!');}

    输出结果为:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4V3CrfjK-1572587509250)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571644156217.png)]

APEX动态运行代码行 (调试|测试)

  1. 打开开发人员控制台( Developer console )

  2. 点击Debug | Open Execute Anonymous Window. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ovCiC68A-1572587509251)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571104642554.png)]

  3. 运行代码:

    ①点击Execute(运行全部)

    ②点击**Execute Highlighted(运行选中部分代码) **

DML

使用数据操作语言(缩写为DML)在Salesforce中创建和修改记录。使用数据操作语言(缩写为DML)在Salesforce中创建和修改记录。

DML语句

语句 作用 语法
insert 新增 insert user;
update 修改
upsert 更新插入
delete 删除
undelete 回复删除
merge 合并
  • insert

    新增单条记录

    // 创建一个客户对象
    Account acct = new Account(Name='Acme', Phone='(415)555-1212', NumberOfEmployees=100);
    // 使用DML插入客户信息
    insert acct;
    //插入记录时,系统会为每个记录分配一个ID。
    //ID值还会自动填充到在DML调用中用作参数的sObject变量上。(也就是说将分配的ID赋值给对象)
    ID acctID = acct.Id;
    System.debug('ID = ' + acctID);
    

    批量新增

    List<Contact> conList = new List<Contact> {new Contact(FirstName='Joe',LastName='Smith',Department='Finance'),new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'),new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'),new Contact(FirstName='Kim',LastName='Shain',Department='Education')};// Bulk insert all contacts with one DML call
    insert conList;
    
  • update

    批量修改

    List<Contact> conList = new List<Contact> {new Contact(FirstName='Joe',LastName='Smith',Department='Finance'),new Contact(FirstName='Kathy',LastName='Smith',Department='Technology'),new Contact(FirstName='Caroline',LastName='Roth',Department='Finance'),new Contact(FirstName='Kim',LastName='Shain',Department='Education')};
    insert conList;List<Contact> listToUpdate = new List<Contact>();
    for(Contact con : conList) {if (con.Department == 'Finance') {con.Title = 'Financial analyst';// Add updated contact sObject to the list.listToUpdate.add(con);}
    }
    update listToUpdate
    
  • Upsert

什么时候用Upsert?

​ 如果你有一个包含新纪录和现有记录的集合,则可以使用Upsert来对所有记录进行插入和更新。

Upsert的优势?

​ 如果集合的记录在数据库中存在,则会更新记录。如果集合的记录在数据库中不存在,则会新增记录。Upsert有助于避免重复记录的创建,并可以节省您的时间,因为您不必先确定哪些记录。

注意:Upsert语句通过比较一个字段的值将”操作的数据“和”数据库中的数据“作对比。

如果你没指定字段,Upsert使用当前对象的ID做对比。

①指定字段

upsert sObjectList Account.Fields.MyExternalId;//指定字段作为对比值

②不指定字段

Contact josh = new Contact(FirstName='Josh',LastName='Kaplan',Department='Finance');
insert josh;
josh.Description = 'Josh\'s record has been updated by the upsert operation.';
Contact kathy = new Contact(FirstName='Kathy',LastName='Brown',Department='Technology');
List<Contact> contacts = new List<Contact> { josh, kathy };
upsert contacts;

Upsert对比结果:

  • 如果字段值不匹配,则会创建一个新的对象记录。

  • 如果字段值匹配一次,则现有对象记录将更新。

  • 如果字段值多次匹配,则会生成错误,并且对象记录不会插入或更新。

  • delete

    删除的记录不会从 Lightning Platform (数据库)上永久删除,但是会将它们放置在回收站中15天内,从那里可以恢复它们。

    语法:

    Contact[] contactsDel = [SELECT Id FROM Contact WHERE LastName='Smith'];
    delete contactsDel;
    

DML语句异常

如果DML操作失败,则返回类型为的异常 DmlException。您可以在代码中捕获异常以处理错误情况。

这个例子产生了一个 DmlException因为它尝试插入没有必填名称字段的帐户。异常捕获在catch块中。

try {Account acct = new Account();insert acct;
} catch (DmlException e) {System.debug('发生了DML异常: ' +e.getMessage());
}

数据库方法

Apex包含内置的Database类,该类提供执行DML操作并镜像DML语句副本的方法。

这些数据库方法是静态的,并在类名上调用。

  • Database.insert()
  • Database.update()
  • Database.upsert()
  • Database.delete()
  • Database.undelete()
  • Database.merge()

与DML语句不同,数据库方法具有可选的allOrNone 参数,该参数使您可以指定操作是否允许部分成功。当此参数设置为false时,如果部分记录操作发生错误,则将提交成功的记录,并为失败的记录返回错误。此外,部分操作成功的记录不会引发任何异常。

Database.insert(recordList, false);

数据库方法返回结果对象,其中包含每个记录的成功或失败信息。

Database.SaveResult[] results = Database.insert(recordList, false);

默认情况下,allOrNone参数是true,这意味着Database方法的行为如果遇到失败,将抛出异常,回滚所有操作。

以下语句的效果一致

Database.insert(recordList);
Database.insert(recordList, true);
insert recordList;

关联操作(主从)

insert关联记录(需要多次DML)

Account acct = new Account(Name='SFDC Account');
insert acct;
ID acctID = acct.ID;
//将客户关联到对应的联系人(需要执行俩次DML)
Contact mario = new Contact(FirstName='Mario',LastName='Ruiz',Phone='415.555.1212',AccountId=acctID);
insert mario;

update关联记录(需要多次DML)

Contact queriedContact = [SELECT Account.Name FROM Contact WHERE FirstName = 'Mario' AND LastName='Ruiz'LIMIT 1];
queriedContact.Phone = '(415)555-1213';
queriedContact.Account.Industry = 'Technology';
update queriedContact;//更新联系人信息
update queriedContact.Account; //更新联系人的客户信息

删除关联记录

delete操作支持级联删除, 如果删除父对象,就会自动删除其子对象。

例如,删除帐户也将删除其相关联系人。

Account[] queriedAccounts = [SELECT Id FROM Account WHERE Name='SFDC Account'];
delete queriedAccounts;

SOQL(类似SQL)

SOQL对象查询语言

SOQL每次查询单个表的数据上限是200,如果超过200条数据,则会再发另外一个请求去查询剩余的数据。

您无需在查询中指定Id字段,因为它始终在Apex查询中返回,除非你只查询ID字段,这个时候则需要指定ID字段。

在查询编辑器中运行查询时,您可能还需要指定ID字段,因为除非指定,否则不会显示ID字段。

当SOQL嵌入Apex中时,称为内联SOQL

Account[] accts = [SELECT Name,Phone FROM Account];

使用查询编辑器

  1. 在开发人员控制台中,单击Query Editor[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y6ehhmiZ-1572587509252)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571127124119.png)]
  2. 输入你要测试的sql,然后点击Execute运行

使用条件过滤查询结果

SELECT Name,Phone FROM Account WHERE (Name='SFDC Computing' OR (NumberOfEmployees>25 AND BillingCity='Los Angeles'))

排序

您可以对大多数字段进行排序,包括数字和文本字段。您无法对富文本格式和多选选择列表之类的字段进行排序。

SELECT Name,Phone FROM Account ORDER BY Name ASC
SELECT Name,Phone FROM Account ORDER BY Name DESC

限制返回的记录数

例如,此查询检索返回的第一个帐户。请注意,当limit 1的时候使用时返回的值是一个帐户而不是数组。

Account oneAccountOnly = [SELECT Name,Phone FROM Account LIMIT 1];

在SOQL查询中调用Apex中的变量

使用:引用变量

String targetDepartment = 'Wingo';
Contact[] techContacts = [SELECT FirstName,LastName FROM Contact WHERE Department=:targetDepartment];

查询关联记录

当查询名称为"SFDC Computing"的客户时,同时查询出该客户对应的联系人

SELECT Name, (SELECT LastName FROM Contacts) FROM Account WHERE Name = 'SFDC Computing'

使用关联查询出来的结果还能通过.调用相关联的数据

Account[] acctsWithContacts = [SELECT Name, (SELECT FirstName,LastName FROM Contacts)FROM Account WHERE Name = 'SFDC Computing'];
// 获取从表数据
Contact[] cts = acctsWithContacts[0].Contacts;
System.debug('Name of first associated contact: ' + cts[0].FirstName + ', ' + cts[0].LastName);

也可以从子表数据调用主表数据

Contact[] cts = [SELECT Account.Name FROM Contact];
Contact carol = cts[0];
String acctName = carol.Account.Name;
System.debug('account name is ' + acctName);

使用外部变量+Like语句

[SELECT Name FROM Contact WHERE Name like :firstName+'%' ]

SOSL

Salesforce对象搜索语言(SOSL)是一种Salesforce搜索语言,用于在记录中执行文本搜索。使用SOSL在Salesforce中跨多个标准和自定义对象记录搜索字段。文本搜索不区分大小写 。

语法:

//IN ALL FIELDS 默认查询全部字段所以可有可无
FIND {bo} RETURNING Contact
FIND {bo} IN ALL FIELDS RETURNING Contact(name)//如果需要指定特定字段查找
FIND {bo} IN Email FIELDS RETURNING Contact(name)//跟在对象后面的字段是返回的内容
FIND {bo} IN ALL FIELDS RETURNING Contact(id,name)//Order by 排序某个字段
FIND {Cloud Kicks} RETURNING Account (Name ORDER BY Name)//limit设置返回的最大记录数
FIND {Cloud Kicks} RETURNING Account (Name ORDER BY Name LIMIT 10)//offset将起始行偏移量设置为结果
FIND {Cloud Kicks} RETURNING Account (Name ORDER BY Name LIMIT 10 OFFSET 25)

这是一个SOSL查询的示例,该查询搜索具有任何字段带有单词“ SFDC”的字段的客户和联系人。

List<List<SObject>> searchList = [FIND 'SFDC' IN ALL FIELDS RETURNING Account(Name), Contact(FirstName,LastName)];

案例:在客户的字段Name,联系人字段FirstName,LastName,Department,中查找值为Wingo的记录

FIND {Wingo} IN ALL FIELDS RETURNING Account(Name), Contact(FirstName,LastName,Department)

SOSL关键字

关键字 作用
IN 限制要搜索的字段类型,包括电子邮件,姓名或电话
LIMIT 指定要返回的最大行数
OFFSET 在多页上显示搜索结果
RETURNING 限制对象和字段返回
WITH DATA CATEGORY 指定要返回的数据类型
WITH DivisionFilter 指定要返回的除法字段
WITH NETWORK 指定要返回的社区ID
WITH PricebookId 指定要返回的price book ID

SOQL与SOSL之间的异同

SOSL与SOQL一样,SOSL允许您在组织的记录中搜索特定信息。与一次只能查询一个标准或自定义对象的SOQL不同,单个SOSL查询可以搜索所有对象。

另一个区别是,SOSL根据单词匹配来匹配字段,而默认情况下(当不使用通配符时)SOQL执行完全匹配。例如,在SOSL中搜索“数字”将返回字段值为“数字”或“数字公司”的记录,但SOQL仅返回字段值为“数字”的记录。

SOQL和SOSL是两种具有不同语法的独立语言。每种语言都有不同的用例:

  • 使用SOQL检索单个对象的记录。
  • 使用SOSL在多个对象之间搜索字段。SOSL查询可以搜索对象上的大多数文本字段。

APEX触发器

Apex触发器使您可以在事件发生之前或之后对Salesforce中的记录(例如插入,更新或删除)执行自定义操作。就像数据库系统支持触发器一样,Apex为管理记录提供触发器支持。

您可以使用触发器来执行在Apex中可以做的任何事情,包括执行SOQL和DML或调用自定义Apex方法。

管理触发器

你可以在此页面上编辑、删除等操作

禁用触发器
  1. 设置中,使用左侧搜索栏搜索Apex 触发器
  2. 点击触发器旁边的编辑按钮
  3. 取消 Is Active的勾选[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0V8XE9GS-1572587509253)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571218889699.png)]

触发器的语法

trigger ContextExampleTrigger on Account (before insert, after insert, after delete) {if (Trigger.isInsert) {if (Trigger.isBefore) {// Process before insert} else if (Trigger.isAfter) {// Process after insert}        }else if (Trigger.isDelete) {// Process after delete}
}

触发上下文变量

变量 用法
isExecuting 如果Apex代码的当前上下文是触发器,而不是Visualforce页面,Web服务或控件,则返回true。 executeanonymous() API调用。
isInsert 如果此触发器是由来自Salesforce用户界面、Apex或API的插入操作触发的,则返回true。
isUpdate 如果此触发器是由来自Salesforce用户界面、Apex或API的更新操作触发的,则返回true。
isDelete 如果此触发器是由Salesforce用户界面、Apex或API中的删除操作触发的,则返回true。
isBefore 如果在保存任何记录之前触发此触发器,则返回true。
isAfter 如果在所有记录都是savec之后触发此触发器,则返回true
isUndelete 如果在从回收站恢复记录后触发此触发器,则返回true。此恢复可以在从Salesforce用户界面、Apex或API执行取消删除操作后发生。
new 返回sObject记录的新版本列表。这个sObject列表只能在insert、update和undelete触发器中使用,记录只能在before触发器中修改。
newMap 将IDs映射到sObject记录的新版本。此映射仅在更新前、插入后、更新后和取消删除触发器后可用。
old 返回sObject记录的旧版本列表。此sObject列表仅在更新和删除触发器中可用。
old map IDs到sObject记录的旧版本的映射。此映射仅在更新和删除触发器中可用。
operationType 返回一个System类型的枚举。对应于当前操作的TriggerOperation。系统的可能值。TriggerOperation enum是:BEFORE_INSERT、BEFORE_UPDATE、BEFORE_DELETE、AFTER_INSERT、AFTER_UPDATE、AFTER_DELETE和AFTER_UNDELETE。如果您根据不同的触发器类型改变您的编程逻辑,那么可以考虑使用switch语句,使其具有惟一触发器执行枚举状态的不同排列。
size 触发器调用中的记录总数,包括旧的和新的。

触发器的实际操作

在触发器内部调用类方法,触发器除了可以在内部改变当前记录的值,还能调用外部的方法

//内部修改值
trigger HelloWorldTrigger on Account (before insert) {for(Account a : Trigger.New) {a.Description = 'New description';}
}
//内部调用外部类方法
//当联系人有新纪录新增或删除时,调用邮箱类的方法发信息给管理员
trigger ExampleTrigger on Contact (after insert, after delete) {if (Trigger.isInsert) {Integer recordCount = Trigger.New.size();// Call a utility method from another classEmailManager.sendMail('Your email address', 'Trailhead Trigger Tutorial', recordCount + ' contact(s) were inserted.');}else if (Trigger.isDelete) {// Process after delete}
}

使用触发器添加关联记录

//当客户记录被新增或者修改时,遍历所有客户对象,如果当前客户没有关联的业务机会,则自动帮客户创建一个关联当前用户的业务机会
trigger AddRelatedRecord on Account(after insert, after update) {List<Opportunity> oppList = new List<Opportunity>();// Get the related opportunities for the accounts in this triggerMap<Id,Account> acctsWithOpps = new Map<Id,Account>([SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New]);// Add an opportunity for each account if it doesn't already have one.// Iterate through each account.for(Account a : Trigger.New) {System.debug('acctsWithOpps.get(a.Id).Opportunities.size()=' + acctsWithOpps.get(a.Id).Opportunities.size());// Check if the account already has a related opportunity.if (acctsWithOpps.get(a.Id).Opportunities.size() == 0) {// If it doesn't, add a default opportunityoppList.add(new Opportunity(Name=a.Name + ' Opportunity',StageName='Prospecting',CloseDate=System.today().addMonths(1),AccountId=a.Id));}           }if (oppList.size() > 0) {insert oppList;}

触发器异常

有时您需要对某些数据库操作添加限制,例如在满足某些条件时阻止保存记录。

以下触发条件可防止删除具有相关业务机会客户。默认情况下,删除客户会导致其所有相关记录的级联删除。此触发器可防止业务机会的级联删除。

trigger AccountDeletion on Account (before delete) {// Prevent the deletion of accounts if they have related opportunities.for (Account a : [SELECT Id FROM AccountWHERE Id IN (SELECT AccountId FROM Opportunity) ANDId IN :Trigger.old]) {Trigger.oldMap.get(a.Id).addError('Cannot delete account with related opportunities.');}}

触发器和标注(Triggers and Callouts)

Apex允许您调用Apex代码并将其与外部Web服务集成。对外部Web服务的Apex调用称为标注。

//标有@future(callout=true)的方法都是异步方法
public class CalloutClass {@future(callout=true)public static void makeCallout() {HttpRequest request = new HttpRequest();// Set the endpoint URL.String endpoint = 'http://yourHost/yourService';request.setEndPoint(endpoint);// Set the HTTP verb to GET.request.setMethod('GET');// Send the HTTP request and get the response.HttpResponse response = new HTTP().send(request);}
}//异步调用外部类方法
trigger CalloutTrigger on Account (before insert, before update) {CalloutClass.makeCallout();
}

触发器批量操作

执行批量SOQL

反例:查询每个客户的业务机会,需要发n次SOQL(n为客户数量)

trigger SoqlTriggerNotBulk on Account(after update) {   for(Account a : Trigger.New) {// Get child records for each account// Inefficient SOQL query as it runs once for each account!Opportunity[] opps = [SELECT Id,Name,CloseDate FROM Opportunity WHERE AccountId=:a.Id];// Do some other processing}
}
如何优化批量SOQL?

将Trigger.New里面所有的客户作为一个集,使用IN查询此集里满足条件的业务机会对象

trigger SoqlTriggerBulk on Account(after update) {  // Perform SOQL query once.    // Get the related opportunities for the accounts in this trigger,// and iterate over those records.for(Opportunity opp : [SELECT Id,Name,CloseDate FROM OpportunityWHERE AccountId IN :Trigger.New]) {// Do some other processing}
}
执行批量DML

反例:将DML操作写在for循环中,会极大的影响其效率。

trigger DmlTriggerNotBulk on Account(after update) {   // Get the related opportunities for the accounts in this trigger.        List<Opportunity> relatedOpps = [SELECT Id,Name,Probability FROM OpportunityWHERE AccountId IN :Trigger.New];          // Iterate over the related opportunitiesfor(Opportunity opp : relatedOpps) {      // Update the description when probability is greater // than 50% but less than 100% if ((opp.Probability >= 50) && (opp.Probability < 100)) {opp.Description = 'New description for opportunity.';// Update once for each opportunity -- not efficient!update opp;}}
}
如何优化批量DML?

创建一个新的集合,装新的记录数据。遍历完之后再执行单个DML操作,操作集合。

trigger DmlTriggerBulk on Account(after update) {   // Get the related opportunities for the accounts in this trigger.        List<Opportunity> relatedOpps = [SELECT Id,Name,Probability FROM OpportunityWHERE AccountId IN :Trigger.New];List<Opportunity> oppsToUpdate = new List<Opportunity>();// Iterate over the related opportunitiesfor(Opportunity opp : relatedOpps) {      // Update the description when probability is greater // than 50% but less than 100% if ((opp.Probability >= 50) && (opp.Probability < 100)) {opp.Description = 'New description for opportunity.';oppsToUpdate.add(opp);}}// Perform DML on a collectionupdate oppsToUpdate;
}

APEX单元测试

编写Test类基本步骤可以分成4步:

1.创建测试数据;

2.调用Test.startTest()方法;

3.调用需要测试的方法();

4.调用Test.stopTest()方法。

测试方法语法

第一种
@isTest static void testName() {// code_block
}
第二种
static testMethod void testName() {// code_block
}
第三种
@isTest
private class MyTestClass {@isTest static void myTest() {// code_block}
}

使用==System.assertEquals()==验证。它有两个参数:第一个是期望值,第二个是实际值。

@isTest static void testWarmTemp() {Decimal number = 10/2;System.assertEquals(5,number);
}

也可以有三个参数,第一个是期望值,第二个是实际值,第三个是测试失败后提示的语句。

@isTest static void testBoilingPoint() {Decimal number = 10/2;       // Simulate failureSystem.assertEquals(0,number,'number 不是预期的值,测试失败');
}

等于运算符(==)执行不区分大小写的字符串比较

在单元测试中,建立代码测试覆盖100%,最低要求75%。

蓝色(覆盖)线和红色(未覆盖)线

如何全部覆盖?

再写一个测试方法保证他能进到红色的代码中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iIdPdtnW-1572587509254)(https://res.cloudinary.com/hy4kyit2a/f_auto,fl_lossy,q_70/learn/modules/apex_testing/apex_testing_intro/images/4177c5d150c4add6e968944ddd37e9de_apex_testing_code_coverage_partial.png)]

查看测试代码的覆盖程度

  1. 在运行完测试类或者测试套件后点击控制台下方的Tests选项卡
  2. 在右侧Overall Code Coverage下能看到每个测试类的结果。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hqqvj3Fo-1572587509255)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571218273379.png)]
  3. 双击某一个测试类还能看到详细的覆盖情况。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CgiXdyGP-1572587509256)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571218310818.png)]

测试套件

创建测试套件
  1. 点击 Test | New Suite
  2. 给测试套件命名
  3. 选择你需要测试的测试类[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KbJD9j5Y-1572587509257)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571216920139.png)]
  4. 点击save保存套件。
执行测试套件
  1. 选择 Test | New Suite Run
  2. 选择你要测试的套件名称,然后单击 **>**移动套件名称到“Selected Test Suites ”列。
  3. 单击Run Suites
  4. 在“测试”选项卡上,监视测试运行的状态。展开测试运行,然后再次展开,直到看到已运行的各个测试的列表。就像在各种测试方法中一样,您可以双击方法名称以查看详细的测试结果。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zgBlccVF-1572587509258)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571217135915.png)]

创建Apex测试的测试数据

我们需要在测试类本身创建测试类的数据。默认情况下,测试类不能访问组织数据,但是如果您设置@isTest(seeAllData = true),那么它将有权访问组织的数据。

在测试类中使用的DML,不会影响真实数据库的数据。并且你还能创建测试数据以便测试。如下:

@isTest
public class TestDataFactory {public static List<Account> createAccountsWithOpps(Integer numAccts, Integer numOppsPerAcct) {List<Account> accts = new List<Account>();for(Integer i=0;i<numAccts;i++) {Account a = new Account(Name='TestAccount' + i);accts.add(a);}insert accts;List<Opportunity> opps = new List<Opportunity>();for (Integer j=0;j<numAccts;j++) {Account acct = accts[j];// For each account just inserted, add opportunitiesfor (Integer k=0;k<numOppsPerAcct;k++) {opps.add(new Opportunity(Name=acct.Name + ' Opportunity ' + k,StageName='Prospecting',CloseDate=System.today().addMonths(1),AccountId=acct.Id));}}// Insert all opportunities for all accounts.insert opps;return accts;}
}

TestMethod关键字

单元测试方法是不带参数,不向数据库提交数据,不发送电子邮件,并在方法定义中使用testMethod关键字或isTest注释声明的方法。此外,测试方法必须在测试类中定义,即用isTest注释的类。

Test.startTest()和Test.stopTest()

这些是可用于测试类的标准测试方法。这些方法包含我们将模拟我们的测试的事件或动作。就像在这个例子中,我们将测试我们的触发器和帮助类来模拟火灾触发器,通过更新记录,我们已经做了开始和停止块。这也为在开始和停止块中的代码提供单独的调节器限制。

System.assert()

此方法用实际检查所需的输出。在这种情况下,我们期望插入一个发票记录,所以我们添加了assert来检查。

@isTest
private class TestAccountDeletion {@isTest static void TestDeleteAccountWithOneOpportunity() {// Test data setup// Create one account with one opportunity by calling a utility methodAccount[] accts = TestDataFactory.createAccountsWithOpps(1,1);// Perform testTest.startTest();Database.DeleteResult result = Database.delete(accts[0], false);Test.stopTest();// Verify that the deletion should have been stopped by the trigger,// so check that we got back an error.System.assert(!result.isSuccess());System.assert(result.getErrors().size() > 0);System.assertEquals('Cannot delete account with related opportunities.',result.getErrors()[0].getMessage());}
}
``
private class TestAccountDeletion {@isTest static void TestDeleteAccountWithOneOpportunity() {// Test data setup// Create one account with one opportunity by calling a utility methodAccount[] accts = TestDataFactory.createAccountsWithOpps(1,1);// Perform testTest.startTest();Database.DeleteResult result = Database.delete(accts[0], false);Test.stopTest();// Verify that the deletion should have been stopped by the trigger,// so check that we got back an error.System.assert(!result.isSuccess());System.assert(result.getErrors().size() > 0);System.assertEquals('Cannot delete account with related opportunities.',result.getErrors()[0].getMessage());}
}

Salesforce-Apex基础相关推荐

  1. Salesforce系列(六):Salesforce Apex基础SOQL查询和数据添加!

    Salesforce系列(六):Salesforce Apex基础SOQL查询和数据添加! 前言 今天博主将为大家分享:Salesforce系列(六):Salesforce Apex基础SOQL查询和 ...

  2. Salesforce系列(五):Salesforce Apex基础SOSL查询和数据添加!

    Salesforce系列(五):Salesforce Apex基础SOSL查询和数据添加! 前言 今天博主将为大家分享:Salesforce系列(五):Salesforce Apex基础SOSL查询和 ...

  3. salesforce零基础学习(八十九)使用 input type=file 以及RemoteAction方式上传附件

    在classic环境中,salesforce提供了<apex:inputFile>标签用来实现附件的上传以及内容获取.salesforce 零基础学习(二十四)解析csv格式内容中有类似的 ...

  4. 【转载】salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解...

    salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解 建立好的数据表在数据库中查看有很多方式,本人目前采用以下两种方式查看数据表. 1.采用schema ...

  5. Salesforce Apex 中常用技能总结(持续更新)

    前言 博主也是Salesforce Apex 工作不久,有用到的知识和平时查阅到的知识和大家分享一下. 总结 1.使用SOQL语句查询时,字符串类型的只能使用'单引号',否则报错:Unknown er ...

  6. salesforce——Apex查询公司财年和财季开始和结束时间(SOQL)

    salesforce--Apex查询公司财年和财季开始和结束时间 关于财年和财季 SOQL查询 关于财年和财季 每个公司一般都会有自己的财年(fiscal year)和财季(fiscal quarte ...

  7. salesforce 零基础开发入门学习(一)Salesforce功能介绍,IDE配置以及资源下载

     目前国内已经有很多公司做salesforce,但是国内相关的资料确是少之又少.上个月末跳槽去了新公司,主要做的就是salesforce,不过当时想要看一些相关资料确实比较难.为了避免想要零基础学 ...

  8. salesforce 零基础学习(十八)WorkFlow介绍及用法

    说起workflow大家肯定都不陌生,这里简单介绍一下salesforce中什么情况下使用workflow. 当你分配许多任务,定期发送电子邮件,记录修改时,可以通过自动配置workflow来完成以上 ...

  9. Salesforce Apex 触发器学习记录

    Apex 触发器(Apex Triggers)是一种特殊的 Apex 类.它的主要作用是在一条记录被插入.修改.删除之前或之后自动执行一系列的操作.每一个 Trigger 类必须对应一种对象. 1.直 ...

  10. salesforce 零基础开发入门学习(四)多表关联下的SOQL以及表字段Data type详解

    建立好的数据表在数据库中查看有很多方式,本人目前采用以下两种方式查看数据表. 1.采用schema Builder查看表结构以及多表之间的关联关系,可以登录后点击setup在左侧搜索框输入schema ...

最新文章

  1. 《大数据分析原理与实践》——小结
  2. DL之DeconvNet:DeconvNet算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
  3. 国内芯片60个细分领域重要代表企业【收藏】
  4. Loj#2035-[SDOI2016]征途【斜率优化】
  5. leaf 叶子(张量)
  6. xcode4的workspace里各lib工程与app工程联编之runscript简介
  7. 获取音、视频时长(NAudio,Shell32,FFmpeg)
  8. 将您重定向的次数过多。_吃鸡:蹦蹦将迎来新皮肤?体验服全面加强,最高时速也不打滑...
  9. 3808. 画正方形——AcWing题库
  10. Apollo课程学习2——高精地图HD Map
  11. linux桌面小程序开发(pyqt+新增csv增删改查功能)附加章节
  12. 光模块有什么用?什么是SFP光模块?
  13. 第一季 停课模拟考试整理(完结)
  14. 文字加下划线单选按钮效果,RadioGroup实现
  15. python实现提取视频里的语音转换为文字
  16. ARCGIS水文分析:水库容量和蓄水区计算
  17. 零售版:GameMaker Studio Ultimate 2022.8.X
  18. “美国老太太”酿造了全球金融危机
  19. 2023.2.11双阶乘
  20. 【验证码逆向专栏】某验三代滑块验证码逆向分析

热门文章

  1. 云原生系列六:容器和Docker
  2. matlab棋盘格标定角点,相机标定(Camera calibration)Matlab——棋盘格标定原理,流程...
  3. MacBook Pro电脑一键切换输入法
  4. Android viewpager2 + indicator 实现页面滑动
  5. Java实现信用卡校验
  6. 软件测试前景怎么样?大概要学什么?
  7. Symmetric diffeomorphic image registration with cross-correlation
  8. 工具教程第三十一讲:电报的使用(二)
  9. linux 服务器加装硬盘流程及sda sdb加载顺序
  10. echarts的中国地图,点击进入省级地图,按需加载对应的省js,可返回中国地图