Friday, October 17, 2014

Loading Test Data ... made my life easier

Hallooo...

I am still here, I forgot that I have a technical blog =)

Okay, I would like to share that something that maybe there for very long time, but I just utilized it recently.

My organization have something that we call Financial Calendar, it is different from our normal life calendar, where by if in our normal life a new year start on every 1 January, our financial start in different month.

Well, it is not big deal except in Salesforce we need to do test class, and most of our classes having logic such the object linked to calendar object, if new quarter come in populate the data etc.

Last time we just use @SeeAllData=true in order to access into this object from test class,but as you and I know it is not advisable as it may lead to other issue.

So we do something like this in our test class.We need to populate record for Financial Calendar in order to use it.

FinancialCalendar__c c1 = new FiscalCalendar__c();
.
.
.

The code goes down , to define the quarter.Oh, FYI, one record in FiscalCalendar store the quarter information such as year,quarter,begin quater date, end quarter date.Imagine if our logic to populate 6 quarter , not to include compare or search the quarter and year by user input plus if we have more than one class using the same object.

But at last, Salesforce introduce this cool stuff. Arrgghh!! Forget whatever code above.I directly query Financial Calendar record, export into .csv format and upload it into Static Resource.

Just to make this code reusable, I put it inside Test Data Factory class.

MyTestDataFactory class.Note FinancialCalendar is Static Resource Name.
@isTest
public class MyTestDataFactory {
    //to create Fiscal Year
    public static void createFinCal (){
         // Load the data from the static resource
         List<financialcalendar__c> lstCal = Test.loadData(FinancialCalendar__c.sObjectType, 'FinancialCalendar');
    
    }
}
MyTestClass
@isTest
public class MyTestClass {

  static testMethod void testReport(){
     Test.startTest();
        List<financialcalendar__c> cals=MyTestDataFactory.createFinCal ();
  //yourcode
  Test.stopTest();
  }
 }

Okay, done.While implementing this, I also faced some difficulty by assuming that the data is not inserted.So I try to put something like

insert lstCal;

right after loadData, and it give me an error because using load data is considered as insert.

*Clap*. Now we can have a mug of hot cocoa with some cookies =)

Friday, August 15, 2014

Invalid constructor syntax, name=value pairs can only be used for SObjects (Line: 90)


If you bumped to this entry, I would like to thank you.I 'll update the content as below.Since my explanation not really helpful at previous post.You still able to view old post at OBSOLETE section below at the end of this post.

I always accidentally face this exception : Invalid constructor syntax, name=value pairs can only be used for SObjects because I instantiate inner class like SObject such as below :

WrapperObj obj = new WrapperObj (paramId=a.Id,isChecked=a.Primary__c,Account=a);

While that only valid for SOBJECT.For inner class, we should use this.Without name value pair.

WrapperObj obj = new WrapperObj (a.Id,a.Primary__c,a);


public class MyExtension {
    
    //other code
    
    public void retrieveInfo(){
        List<WrapperObj >  listAccountObject = new List<WrapperObj > ();
        List<Account > listAccount = [Select Id,Primary__c from Account  where Id=:acct.Id];
        
        if(listAccount.size()>0){
            for(Account a: listAccount ){
        //INVALID WAY FOR CONSTRUCTOR#2
              WrapperObj obj = new WrapperObj (paramId=a.Id,isChecked=a.Primary__c,Account=a);
  
    //CORRECT WAY FOR CONSTRUCTOR#2
     WrapperObj obj = new WrapperObj (a.Id,a.Primary__c,a);
     
    //ANOTHER CORRECT WAY FOR CONSTRUCTOR#1
     WrapperObj obj = new WrapperObj ();
     obj.paramId=a.Id;
     obj.isChecked=a.Primary__c;
     obj.myAccount=a;
              
           }
  }
    }
    
 //inner class
    public class WrapperObj {
    
         public String paramId {get;set;}
         public Boolean isChecked {get;set;}
         public Account myAccount {get;set;}
         
   //CONSTRUCTOR#1
         public WrapperObj(){
  }
  
   //CONSTRUCTOR#2
         public WrapperObj (String paramId,Boolean isChecked,Account acct){
            this.paramId=paramId;
            this.isChecked=isChecked;
            this.myAccount=acct;
    
         }

    }
}

Have a nice day.

Thanks.
-------------------------------------------OBSOLETE---------------------------------------------------------
*Yawn* Sometimes the best of us always forget the basic one.

If we create inner class , it is not allowable to instantiate it like we always do for standard object as below:

Series s = new Series(name='s1');

We should instantiate and define using longer way like this:

Series s=new Series();
s.name='s1';

Good Luck~


Thursday, July 17, 2014

Writing sign for URL ...write signature for Google Geocoding API

I have chance to work with Google Geocoding API lately...in Salesforce of course.

The requirement is to retrieve address from Google Geocoding by passing postal code.When passing postal code through HttpRequest, it should return the response in JSON.But I am not going to write how I call it in this entry.I will save it for future.*cough*
So I will write on how to generate signature...
Note on this limitation between free API and paid one.

Users of the free API:
  • 2,500 requests per 24 hour period.
  • 10 requests per second.
Maps for Business customers:
  • 100,000 requests per 24 hour period.
  • 10 requests per second.
To create API you can go here .Use our own Google account.But I found out without API key also it works.

See!!This is free...you can play around with it.
https://maps.googleapis.com/maps/api/geocode/json?components=postal_code:97510

So I go for Maps for Business customers, what is that mean?
It means , we required to have client and signature.

Google will give us client and private key.But it does not mean that we are on now.We need generate the signature using private key given.Each time when we request for postal code, we need to generate signature.
Example, postal code different so signature also can be different.

https://maps.googleapis.com/maps/api/geocode/json?components=postal_code:11900&client=gme-acme&signature=signature1

https://maps.googleapis.com/maps/api/geocode/json?components=postal_code:11800&client=gme-acme&signature=signature2

Actually it sound like a lot of job to generate signature.It is not fun because only Phyton and Java examples that available.I need to generate signature before calling the webservice.Calling out itself have limitation in Salesforce.*sigh*

But I after done some research, do experiment ,asking around ...at last I managed to generate the signature in Apex class.One of the forum that inspired me is here . But it seem that I need to play around with replace method  before execute urlEncode.

Anyway, here the code.Note for this we need to use hmacSHA1 algorithm.
You can go ahead and run in Apex Execute Anonymous, but make sure that you have the client and private key.Hope it will help you.I could not guarantee it is error free, but it works for me.Let me know if you have better solution.

*Because this is for corporate use, go ahead and ask Google support.

//replace the number with any postal code to test
String baseUrl = 'https://maps.googleapis.com/maps/api/geocode/json?components=postal_code:97005&amp;client=gme-acme';
URL url = new URL(baseURL);
String path =url.getPath();
String query=url.getQuery();
String input=path+'?'+query;

String privateKey='whateverkeythatyougot';

Blob decodePK = EncodingUtil.base64Decode(privateKey);
String algorithmName = 'hmacSHA1';
Blob hmacData = Crypto.generateMac(algorithmName, Blob.valueOf(input), decodePK);

String encodePK =EncodingUtil.base64Encode(hmacData);
//please make sure to replace.
encodePK = encodePK.replace('+', '-');
encodePK = encodePK.replace('/', '_');
String signature =EncodingUtil.urlEncode(encodePK, 'UTF-8');
signature = signature.replace('+', '-');
signature = signature.replace('/', '_');

baseUrl +='&amp;signature='+signature;

//this is the final URL that  can be pasted to browser
system.debug('@unid baseURL ='+ baseURL);

References:
Google Geocoding API
Digital Signature
Stack Overflow
Salesforce Crypto Class

Wednesday, June 04, 2014

Clone User in Salesforce

I need to create sample of users to test one of the application.It is TEDIOUS to do data entry one by one.If two still okay for me, if five ...ten...better I start  Googling.

Heh...although I know the Clone feature is exist in Salesforce but I just found out that for User there is no Clone feature directly.There work around to Clone it.Someone posted an idea for Clone User, please vote it if you feel it is useful for you.I voted it already =)

Vote  idea for Clone Users : https://success.salesforce.com/ideaView?id=08730000000BpK9AAK

Once you vote it, don't forget to read the comments.You'll be surprise a lot of suggestion of workarounds there.The entry that I wrote today was my experiment based on the workaround suggested.

In order to make Clone User feature , just follow the step below:

1 - Go to Setup --> App Setup --> Customize --> Users. Add Custom Links as below.
Label : Clone User
Behavior : Display in existing window with sidebar
Button or Link URL :/{!User.Id}/e?clone=1&retURL=%2F{!User.Id}&isdtp=mn


Don't forget to Save.

2-Add this new Custom Link at User Layout.Again don't forget to Save.

3-Now you can go and check the Custom Link at the User page.
It's there!!!
4- You click that link, fill in necessary fields and Save.The UI is similar like below.
Cooolll like ABC!!
However  I still hope that Salesforce will provide Standard button to clone the user.

For this time being, this workaround  is SAVING my day. =)

Tuesday, May 20, 2014

Get SOSL covered during Apex Test Execution.

Why my SOSL returning no data during testing??
I created sample data, I saw it in log.I swear but why it return no data?

Why?
Why?

The hair drop one by one...the wrinkle become finer and finer.She stay quietly facing her laptop.She did not notice that her age is multiplying hastily..

.
.
.

Stop all the drama, let see the point here.The possibility why SOSL not returning data during Apex Test Execution is because Salesforce designed it that way!

WHAT!!!

Yes, to ensure test class run in predictable way they decide to not return data when you use SOSL.
To ensure that test methods always behave in a predictable way, any Salesforce Object Search Language (SOSL) query that is added to an Apex test method returns an empty set of search results when the test method executes. If you do not want the query to return an empty list of results, you can use the Test.setFixedSearchResults system method to define a list of record IDs that are returned by the search. -more info.
Okay, so we can use this Test.setFixedSearchResults.I gave example how to use it like below.Note that it only show how we can test SOSL NOT how to implement SOSL.
@isTest
private class MyControllerTest{ 
 
    private static Account acc1;
   //set up data for each test method
    static {
      acc1 = new Account(Name='MyFatherCompany',Description__c='Produce stuff');
      insert acc1;
      System.assertEquals(1,[select count() from Account  where Name = 'MyFatherCompany' ]);
     
    }
    static testMethod void test1(){
        Test.startTest();
            //Apply the setFixedSearchResults here
             Id [] fixedSearchResults= new Id[1];
             fixedSearchResults[0] =acc1.Id;
             Test.setFixedSearchResults(fixedSearchResults);
        
              MyController obj = new MyController();
             
             obj.custname=acc1.Name;
             obj.searchUsingSOSL(); //This code is contain SOSL.
      
        
        Test.stopTest();
    }
 }

Now you will see the data, and the method that process those data should be covered and you should live happily ever after.=)

Making the private access modifier visible during test execution.

Whenever I got error  like below during test execution, I will go directly to the class and change the access modifier from private to public.It is not proper because each access modifier serve different purpose, so it is not quite acceptable to modify it just to get PASS for testing.Seem unacceptable but I did it a lot of times. *Evil smile*


But I accidentally find proper solution for this.I posted it in my company site, but I m thinking to share it here.We can use @TestVisible ... @TestVisible everyone.I don't  notice since when it available, but I just noticed it yesterday.Shame!

Well, let's start experiment it.I am using Force.com free edition sandbox to test this.You can find this free sandbox here.

This is my class, notice the private stuff.Private variable and method.

public class MyClass{
    // Private member variable
    @TestVisible private static Integer recordNumber = 1;

    // Private method
    @TestVisible private static void updateRecord(String name) {
       recordNumber =recordNumber +1;
     }   
}

Here the test class.

@isTest
private class MyClassTest {
    @isTest static void test1() {
        // Access private variable annotated with TestVisible
        Integer i = MyClass.recordNumber;
        System.assertEquals(1, i);

        // Access private method annotated with TestVisible
        MyClass.updateRecord('RecordName');
        // Perform some verification
    }
}

If you remove @TestVisible, and run the test class you will get the above error.So now instead of changing the access modifier, bear in mind to put @TestVisible whenever you have private stuff to be tested.

Do not reveal your secret just because you want to pass the exam!Keep some mysterious remain.

Please dig more info about @TestVisible here. Have a very nice day ahead. =) .



Friday, May 09, 2014

How to save email thread in GMail into PDF?

This is very easy.I found it when I try to print email thread.This function is there since very long time but I just recognize it today.(-_-)Y


Use the Print icon at the top of the email to print/save as .pdf the whole email thread.If you want to print one email, then use the Print in the sub menu.

Okey bye.Happy Friday.

Wednesday, May 07, 2014

Why we need to use XmlStreamWriter?

Sometimes we [maybe only me] choose the simple method to achieve something.Well, if the objective is done, what else we need to think.

Actually I just want to write about XMLStreamWriter.Some code that I reviewed using simple method to generate XML, which is by appending the string.Well thinking that I going to be safe,I just proceed appending the string like example below.
Example
 String xmlStr ='<user xmlns:i="http://www.w3.org/2001/XMLSchema-instance">';
  if(displayName!=null)
  xmlStr+='<displayname>'+displayName+'</displayname>';
  if(Group!=null)
  xmlStr+='<group>'+groupName+'</group>';
  xmlStr+='</user>';
It goes well after quite some time until one day ,a user shout out about an error. 500 : There was an error deserializing the object of type bla bla.. Whenever a programmer face error, we will google it =) .I notice there & symbol in the data and it caused the issue.So the proper way to write xml is by using XmlStreamWriter.
XmlStreamWriter  w= new XmlStreamWriter();
 w.writeStartElement(null, 'User',null );
 w.writeNamespace('i','http://unid-machine.blogspot.com');
 w.writeStartElement(null,'DisplayName',null);
 w.writeCharacters('Unid');
 w.writeEndElement();
        w.writeStartElement(null,'Groups',null);
        w.writeStartElement(null,'Group',null);
        w.writeCharacters('Group1');
        w.writeEndElement();
        w.writeStartElement(null,'Group',null);
        w.writeCharacters('Group2');
        w.writeEndElement();
        w.writeEndElement(); //groups
 w.writeEndElement();
 
        system.debug('@Xml string '+ w.getXmlString());
Okay, bring it on user whatever data you like =) . The example of output
<user xmlns:i="http://unid-machine.blogspot.com">
<displayname>Unid</displayname>
<groups>
<group>Group1</group>
<group>Group2</group>
</groups>
</user>
Reference:XmlStreamWriter

Tuesday, April 08, 2014

Invalid_session_id when try to create Force.com project using Eclipse.

I am not sure why since yesterday I could not create project using Force.com IDE.This is my first time error and I have been creating a lot of project using this IDE before.


So I google and see this interesting issue here.

It mentioned that we should go to Setup --> Security Control --> Session Setting and make sure
'Lock sessions to the IP address from which they originated' is UNCHECK.


Interesting, I checked the Session Setting unfortunately it already in unchecked mode.Pondering here and there and at last I restart my machine.FYI, my machine is in hibernate mode for few days.I am lazy to shutting it down, so I just set it to hibernate.

Magically-after restart and create the project again, the issue won't come anymore.Is it something to do with restarting the machine?I still wondering what the scientific reason behind this but it works.

So in case, you face this type of issue-you can try to restart your machine and PRAY. 

See ya again. Thanks for reading this . =)

Oh ya, a beneficial link regarding Setting Session Security -I got this from my colleague.

Wednesday, March 05, 2014

Testing Http call out using StaticResourceCalloutMock

I was working with the Http call out stuff lately and have a chance to learn on how to execute test class on this type of class.Test class...not my favorite subject in salesforce but it is very important :).

I did some googling stuff and also bump into implementation of HttpCallout mock interface-- it was like phew! But I also bumped into other option which is StaticResourceCalloutMock and MultiStaticResourceCalloutMock which seem pretty easier.

Okay let's get started!

What is StaticResourceCalloutMock?
Built-in class used to test our callouts by specifying the response body in Static Resource.

Why?
Easy instead of implement code using HttpCalloutMock interface.We just create dump response file in Static Resource then instantiate the StaticResourceCalloutMock.

Scenario:
I have class that call webservice from other server in order to get the token.It call the webservice using Http call out.So in order to let it deployed beautifully in production , I need to get higher 75% mark in test coverage.

This is the class that using Http call out.

public class GetTokenClass {
 
 public Integer statusCode ;
 public String errorMessage;

   public String getToken()

    {
     String baseUrl='www.myDomain.com/2.0/Authentication/SalesForce';
 
       HTTPRequest r = new HTTPRequest();              
       r.setEndpoint(baseURL);
       r.setMethod('POST');
       r.setTimeout(120000);
      
        HTTP http = new HTTP();
        HTTPResponse response = http.send(r);      
        XmlStreamReader reader = response.getXmlStreamReader();
               
       String  accessToken = '';
   
        if(response.getStatusCode()!=200){
           errorMessage=response.getStatusCode() +' : '+ response.getStatus();
          
         }
        else {
         while(reader.hasNext()) { 
          if (reader.getEventType() == XmlTag.START_ELEMENT) {
             if(reader.getLocalName() == 'input'){               
                string token_id = reader.getAttributeValue(null, 'id');
  
             if(token_id == 'access_token')
                  {
                      accessToken = reader.getAttributeValue(null, 'value');
                  }
              }
          }
         reader.next();
         }
        }
         statusCode=response.getStatusCode();
        
        return accessToken;
}
}

So these are the steps that I need to do in order to use StaticResourceCalloutMock .

1) Create Static Resource that contain the response body.In my case, I need to retrieve xml file.So I will upload xml file below in Static Resource.I put the name as TokenTest.




 2)Create the test class, specify the Static Resource name that previously upload.
@isTest
public class MyTestClass {
static testMethod  void testGetToken(){
     GetTokenClass  controller = new GetTokenClass();
     StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
     mock.setStaticResource('TokenTest');
        mock.setStatusCode(200);
        mock.setHeader('Content-Type', 'text/xml');
        
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, mock);
     controller.getToken();
     Test.stopTest();
 }
}


 3)Run the test classs.That's all.

 Note:If we have many call out in one class- we might want to consider MultiStaticResourceCalloutMock. 

References Testing HTTP Callouts Using Static Resources