Minimize and Optimize Apex Test Classes with SmartFactory

I was writing allot of test code to create SObjects and all the necessary fields. There are some problems when writing test code when specifying all the necessary fields.

Some of the things to consider when creating test fields is required fields and pre-populating lookups. Let us look at some examples:
Let’s start of creating a Account in a Test Class:

Account newAccount = new Account(Name='This is a Test Account');

Now we create the Contact associated to that Account:

Contact newContact = new Contact(AccountId=newAccount.Id);

but Contact has more required fields and will fail if I call the:

 insert newContact;

Let’s take it a bit further and create an Opportunity and select the newAccount.

Opportunity newOpportunity = new Opportunity(AccountId=newAccount.Id);

the same story for opportunity is we need more required fields to be completed, and do we always know the required fields?No for some unknown Salesforce orgs this may be a problem.

Let’s see how we can solve the problem of required fields and lookup during sObject creation:

Contact c = (Contact)SmartFactory.createSObject('Contact', true);

The second argument (true) toggles the cascade option, which populates any lookup fields on the object with their own newly created objects. It’s a powerful way to create hierarchies of test data quickly and easily so you can focus on writing test and implementation logic.

Now we can create an Opportunity without specifying an Account or Contact:

Opportunity o = (Opportunity)SmartFactory.createSObject('Opportunity', true);

This will create, a Account, Contact and Opportunity for you in one line.

SmartFactory uses the describe metadata to populate all fields with data of the right type. It currently handles string and lookup fields. For lookup fields, it creates an appropriate object and then uses that object’s ID.

Salesforce Update Product Schedule from Opportunity Product using Apex Trigger

Update the Product ScheduleDate when the Opportunity Product ServiceDate changes. First we create an OpportunityProduct Trigger to see when ServiceDate changes and parse the amount of days difference between the old and new date.

trigger ProductDateUpdate on OpportunityLineItem (after update) {
   
    for (OpportunityLineItem oli: Trigger.new) {
        OpportunityLineItem oldCloseDate = Trigger.oldMap.get(oli.ID);
        if (oli.ServiceDate != oldCloseDate.ServiceDate) {
            Integer dateval = oldCloseDate.ServiceDate.daysBetween(oli.ServiceDate);
            ProductScheduleUpdate.ScheduleProductUpdate(oli.id, dateval);  
        }
    }
}

The Trigger class then updates all the Product Schedule Dates by the amount of days.

public class ProductScheduleUpdate
{
    public static void ScheduleProductUpdate(String oid, Integer dateval)
    {
           List datelist;
           datelist = [SELECT ScheduleDate FROM OpportunityLineItemSchedule WHERE OpportunityLineItemId =:oid];
           for (Integer k = 0; k < datelist.size(); k++)
               {
               System.debug('DateList = ' + datelist[k]);
               Date mydate=Date.newInstance(datelist[k].ScheduleDate.Year(),datelist[k].ScheduleDate.Month(),datelist[k].ScheduleDate.Day());
               mydate=mydate.addDays(dateval);
               datelist[k].ScheduleDate = mydate;
               update datelist;
               //date datediff = date.parse(datelist[k]);
               }
        
    }
}

Salesforce Update Product Schedule from Opportunity using Apex Trigger

The tutorial below shows how you can use Salesforce Triggers to update the CloseDate of an opportunity and the associated Product Schedule.

First thing is we must create a product Trigger, below is the code for the product trigger:

trigger OpportunityScheduleUpdate on Opportunity (after update) {
  
  for (Opportunity o: Trigger.new) {
        Opportunity oldCloseDate = Trigger.oldMap.get(o.ID);
        if (o.CloseDate != oldCloseDate.CloseDate) {
            Integer dateval = oldCloseDate.CloseDate.daysBetween(o.CloseDate);
            OppScheduleUpdate.ScheduleDateUpdate(o.id, dateval);  
        }
    }
}

The trigger class updates all the Product ScheduleDate by the amount of the days the Opportunity Close Date has changed:

public class OppScheduleUpdate
{
    public static void ScheduleDateUpdate(String oppid, Integer dateval) 
    {
       List idval = [SELECT id FROM OpportunityLineItem WHERE OpportunityId=:oppid];
       List datelist;
       for (Integer i = 0; i < idval.size(); i++)
       {
           datelist = [SELECT ScheduleDate FROM OpportunityLineItemSchedule WHERE OpportunityLineItemId =:idval[i].id];
           for (Integer k = 0; k < datelist.size(); k++)
               {
               System.debug('DateList = ' + datelist[k]);
               Date mydate=Date.newInstance(datelist[k].ScheduleDate.Year(),datelist[k].ScheduleDate.Month(),datelist[k].ScheduleDate.Day());
               mydate=mydate.addDays(dateval);
               datelist[k].ScheduleDate = mydate;
               update datelist;
               //date datediff = date.parse(datelist[k]);
               }
       }      
    }
}

Salesforce Apex check field updated trigger

The code below show how you can use oldMap.get to get the previous value of a field after an update has been made in Salesforce. In this case I calculated how many days a specific date has been updated with:

trigger CaseOnParticularFieldUpdate on Case (before update) { 
for (Case c: Trigger.new) { 
Case oldCase = Trigger.oldMap.get(c.ID); 
if (c.Field != oldCase.Field) { 
// field was updated, do some magic here } } }

Salesforce Sites.com vs Force.com Sites

Site.com

  • Sites.com is meant for business users as there is no coding mandatory. Business users can easily create their own websites and it uses a Sites.com Guest User License.
  • Public (unauthenticated) sites only which means no Authentication are supported
  • Custom coding using HTML, CSS, Javascript, No VisualForce, Apex support as of now.
  • CRM Content objects are not supported. Allows read only access to some objects through the objects data elements.
  • Two types of users – Publisher and Contributor. Publisher is super set of Contributor.
  • Chatter supported for contribution of content while chatter is not available on the front end website.
  • Drag n drop support for CMS.

Force.com Sites

  • Force.com sites supports both authenticated and public websites
  • Support for custom pages using VF, JS, CSS etc
  • Main targe audience is developers
  • Access to all Force.com objects

Persistent Systems at Salesforce CloudStock Event

Visit Persistent Systems (www.persistentsys.com) at booth number 31C to learn how Persistent Systems can help you build a Social Enterprise. Come learn about the projects that Persistent are currently working on revolving around Force.com, Database.com, Chatter and Heroku based custom application and product development.

If you’re an enterprise just starting out with Force.com, Persistent offers an assessment tool that will analyze your current applications and help you understand which applications make sense to move to the cloud map out plan to get there.

If you’re an ISV considering the development of a SaaS product, Persistent can help get you there successfully, just as we did with BMC Software, Jigsaw, Radian6, and many others.

Visualforce Standard vs Custom Apex Chart

The Visualforce chart below is key to understand how customization and development work in Salesforce.

Standard Behavior Custom Behavior
Standard Look and Feel Application Framework and Default UI (Page Layout)Example: Standard Opportunity page with a default page layout. Page Layouts and Custom Apex ClassesExample: Standard Opportunity page that validates the opportunity stage.
Custom Look and Feel Visualforce pages with standard controllersExample: Visualforce page containing opportunity information Visualforce pages with custom Apex ControllersExample:Opportunity search portal to search for specific opportunities in Salesforce.