+ Start a Discussion

Unit Testing and History Table

Has anyone had any luck unit testing against information in the history table for an object?


We have a custom history popup, similar to the SF history display, but generated from scratch in a VisualForce controller.


I'm attempting to write some unit tests for the controller.  I am creating and updating an object of a type which has history tracking turned on, but I never get any entries in the history table.  I'm assuming that this is because the history table is populated from a trigger or similar when the transaction commits, and the transaction is rolled back in test mode.


I'm going to restructure to the code to get around this from the coverage point of view, but before I do that I'd appreciate it if anyone could confirm that this is the case.


This isn't a specific answer, but if your assumption is correct ...


During Unit Testing: always assume your data is completely empty. This will save you when attempting to execute tests in a new org or sandbox. If you follow this advice, you should build up multiple transactions on you object tho create the history during that test.


I am building up my data from scratch. 


I insert an object, update it and then attempt to query the information associated with it from the history table.  Trouble is, the result of the SOQL query against the history table is always empty.


You mention building up the data for the object using multiple transactions - how is this possible?  I thought that tests took place in a single transaction and were rolled back at the end.  Thus I can never build my data up, as its always discarded.


It sounds like you're doing it correctly. The data is rolled back after the the test method exits. So if you're performing those transaction in one test method, then I would assume your data should be there.

Therefore, you may need to look for a different issue.

There are definitely some holes in the testing framework and it sounds like this may be another one. I'll be curious to hear if you were able to address this without querying existing data.
Message Edited by TehNrd on 08-12-2009 01:56 PM

I as able to get coverage up into the high 90%, but only after restructuring my code to split the database query out to a separate method from that which processes the results.  Then in my unit tests I had to fake up some history objects and invoke the method that processes the results directly with these fake objects. 


The problem was further compounded by the fact that most of the fields in History object are read-only!


I agree about the holes in the testing framework - particularly glaring if you have a background with JUnit or TestNG.


I was able to get 100% coverage by just querying the Account History table with a limit, and returning my results...I did insert an Account beforehand.  I hope this helps.



 // Initialize list to be returned
     list<cHistories> list_ch = new list<cHistories>();
     // Loop through all field history records
     for (AccountHistory fh: [select 
          From AccountHistory
                   order by CreatedDate desc
           Limit 2]) { 
       System.assert(fh.getsObjectType() == AccountHistory.sObjectType);

<!-- bunch of code in between to translate/transform data returned Then:-->

        ch.FieldLabel = fieldName;
        ch.fromValue = fromText;
        ch.toValue = toText;
        System.assertEquals(fieldName ,ch.FieldLabel);
        System.assertEquals(fromText ,ch.fromValue);
        System.assertEquals(toText, ch.toValue);
        System.assertEquals(ch.theDate, String.valueOf(fh.createddate));




This was the same for me if I had information in the history table already, but didn't work for an installation into a clean environment.   Does the account that you have inserted appear in your results?


I encountered this issue when tests were executing during a managed package installation, in that I couldn't get anything in to the history table in order to check that my custom history page was working.  My understanding is that the information goes into the history table once the transaction is committed, but as the test transaction is rolled back, nothing makes it into the table. 


What I really ended up doing - since the code above didn't seem to be calling any of the class methods I was testing, was to figure out how to call the method. 


The class I have takes the account and looks up it's history objects and returns a list. 


So for testing the list, I finally succeeded with this, still not at a100% but it is enough to deploy:



public class AccountExtTests {
 public static void testAccountExt() {
   Account a;
   //get a random account
        a =  [select id, name from Account Limit 1];
        System.assertEquals(a.getsObjectType(), Account.sObjectType);
    PageReference pageRef = Page.TabbedAccounts;
    ApexPages.currentPage().getParameters().put('id', a.id);
    ApexPages.standardController controller = new ApexPages.standardController(a);

    AccountExt extension = new AccountExt(controller);
//here is where the Method is called in the class    
     list<AccountExt.cHistories> list_ch = extension.getHistories();  
     AccountExt.cHistories ch = new AccountExt.cHistories();
     String fieldName = 'Owner';
     String theDate = '10/1/2010 10:38 AM'; 
     String who = ' Eva DeLorio';
     String fromText = 'Sheila';
     String toText = 'Robert';  
        ch.FieldLabel = fieldName;
        ch.fromValue = fromText;
        ch.toValue = toText;
        ch.who = who;
      System.assertEquals('Eva DeLorio',who);
public class cHistories{
      Public String theDate = '10/1/2010 10:38 AM'; 
      Public String who = ' Eva DeLorio';
      Public String action; 
      Public String fieldLabel = 'Owner';
      Public String fromValue = 'Sheila McEvoy';
      Public String toValue = 'Robert Akin ';    


I have an if statement in my class that I just can't seem to get into or around with this test. 




FYI in case this helps anybody. I was having this problem too and confirmed with Salesforce Developer Support that there is no way to test anything to do with history since none of the data is ever committed during a unit test.


I think this last post is the best idea. Building off of that, you can just create a class or map to hold the history data then if a test is running, return sample data instead of querying data. I use a similar strategy to get test coverage for HTTP Callouts.