Sunday, 20 November 2022

Apex offers two ways to perform DML operations

Apex offers two ways to perform DML operations:


1. DML statements :


Eg : Insert Acc ;


This is more straightforward to use and result in exceptions that you can handle in your code.


2. Database class methods :


Eg: Database.insert(Acc, false);


By using the Database class method, you can specify whether or not to allow for partial record processing if errors are encountered. If you specify false for the second parameter and if a record fails, the remainder of DML operations can still succeed.


Instead of exceptions, a result object array (or one result object if only one sObject was passed in) is returned containing the status of each operation and any errors encountered.


So how do you choose between the two options available?


If you need the errors that occur during DML to be thrown as an Apex exception that immediately interrupts control flow --> then go for DML statements


If you need to allow partial success of DML. Using the Database class methods, you can write code that never throws DML exception errors. Instead, your code can use the appropriate results array to judge success or failure. --> then go for Database class methods


PS : Database methods also include a syntax that supports thrown exceptions, similar to DML statements.

Tuesday, 15 November 2022

New Salesforce Assert Class

 Using Assertion.Fail() to intentionally return a fatal error.

Using Assertion.isInstanceOfType() to assert object instance.


ex : 


try {

    Test.startTest();

    SomeClass.someMethod();

    System.Assert.Fail('Throw custom exception);

 } catch (Exception baseException) {

     System.Assert.isInstanceOfType(baseException, 

                                   SomeClass.SomeCustomException, 

                                   'Expected an instance of SomeCustomException');

 }

  

Using Assert.isNull() to assert the null values.


 ex :  

  Opportunity opp = OpportunityService.getRecentClosedOpportunity();

  System.Assert.isNotNull(opp, 'Expected the opportunity to not be null'); 

  System.Assert.isNull(calloutResponse, 'Expected a null response');


Using Assert.areEqual() instead of System.assertEquals() for clarity.


ex : 


Account acc = new Account();

acc.Name = 'Test Account';

insert acc;

System.Assert.areEqual('Test Account', acc.Name, 'Expected account name to be Test Account');


String sub = 'abcde'.substring(2);

System.Assert.areNotEqual('xyz', sub, 'Characters not expected after first two');


Using Assert.isTrue() instead of System.assert() for clarity.


ex:   

  

Boolean containsForce = 'Salesforce'.contains('force'); 

System.Assert.isTrue(containsForce, 'Expected true result.');

System.Assert.isFalse(containsForce,'Expected false result.');

System.Assert.isTrue(insertResults.isEmpty());


Note :


Write System.Assert.areEqual instead of Assert.areEqual and you can safely use the new classes.

Sunday, 13 November 2022

Upgrade Behavior Options of Unlocked Packages :

 Options when installing the unlocked packages.

1.Mixed Mode (Default behavior) :

Specifies that some removed components are deleted, and other components are marked deprecated.

2.Deprecate Only :

DeprecateOnly specifies that all removed components must be marked deprecated. 

The removed metadata exists in the target org after package upgrade, but is shown in the UI as deprecated from the package. 

This option is useful when migrating metadata from one package to another.


3.Delete :


Delete specifies to delete all removed components, except for custom objects

and custom fields, that don't have dependencies.

ex :

sfdx force:package:beta:install --package 04t... -t DeprecateOnly


Monday, 7 November 2022

Pre-requisites for creating Second-Generation Managed Packages

 1. Enable Dev Hub in your Org.

2. Enable Second-Generation Managed Packaging.

3. Install Salesforce CLI.

4. Create and Register Your Namespace


Note : Developers who work with 2GP packages need the correct permission set in the Dev Hub org.

       Developers need either the System Administrator Profile or the Create and Update Second-Generation Packages permission.

       

Namespace:


1.The namespace of a managed package is created in a namespace org and linked to the Dev Hub.

we can associate multiple namespaces to a single Dev Hub.

A namespace is linked with a 2GP when you run the force:package:create Salesforce CLI command And you must specify the namespace in the sfdx-project.json file.


2.Multiple packages can use the same namespace.


3.Multiple packages sharing the same namespace can share code using public 

Apex classes and methods @namespaceAccessible annotation.


 

How to register/link a namespace ?


Login to your Dev Hub org as the System Administrator or as a user with the Salesforce DX Namespace Registry Permissions.


Some of the orgs that you use with second-generation managed packaging have a unique purpose.


1.Choose your Dev Hub Org.

2.Namespace Org.

3.Other Orgs.



Purpose of Dev Hub :


As owner of all second-generation managed packages.

To link your Namespaces.

To authorize and run your force:package commands.

Note : Salesforce recommend that your Partner Business Org is also your DevHub Org.


Purpose of Namespace Org :


The primary purpose of the namespace org is to acquire a package namespace.

If you want to use the namespace strictly for testing,choose a disposable namespace.


After you create a namespace org and specify the namespace in it, open the Dev Hub org 

and link the namespace org to the Dev Hub org.


purpose of Other Orgs :


When you work with packages, you also use these orgs: you can ceate scratch orgs on the fly to use while testing your packages.

The target or installation org is where you install the package.

Behavior of Salesforce data in Apex tests

 1.Existing org data isn't visible to Apex tests.

2.As a best practice you should always create your own test data for each test.


Reasons to create your own test data :


1.Data unavailability

  your org might not have the data for both positive and negative tests.

2.Data inconsistency

  Data can be different between orgs and test runs.


Note : In some scenarios like testing report data or field history records 

        you might need to have access to our org data because you can't create 

         those records through apex.

       In those cases you can annotate your test class with 'seeAllData' is equal to true annotation.


  ex : @isTest(seeAllData=true)

       public class DemoCtrlTest{

          

          @isTest

          static void testAccountFilter(){

          

          }

       

       }  


3. Apex test data is transient and isn't committed to the database.


Note : which means the data is present only as long as your test is running.


4.Testsetup methods are helpful test setup methods are defined in a test class itself

   they take no arguments and no return a value.

   

   ex 

      @istest

      public class DemoCtrlTest{

      

      @testSetup 

       static void createTestData(){

         // create test data here

       }

      }


a. Test setup method is automatically executed first, before any test method.

b. Records created in the test setup method are accessible to all test methods.

c. Changes to records by a test method are rolled back before another test method is executed.

d. All records are rolled back after the test class finishes executing.


create test data using CSV file :


ex : @testSetup 

      static void creatTestData(){

        Test.loadData(Account.sobjectType,'Mock_Account_Data');

      }   


Test Data and Governor Limits :


Whenever a test class runs the test data creation and test execution both happens in the same transaction.   


ex : 

Test.startTest();

Test.stopTest();


The startTest() method marks the point in your test code where the test 

actually begins and stopTest() method marks the point where your test ends.


Any code that executes between these two methods is assigned a 'new set of governor limits '.

The code inside start and stop block has one set of limits and the code outside has another set of limits.

The code outside whether before or after that start and stop methods shares the same limit.