-3

Here is my test class

public class BoothChangeReportCtrl {

    @auraEnabled
    public static List<BoothChangeDetail> getBoothChangeData(){
        List<BoothChangeDetail> BoothChangeWrapperList = new List<BoothChangeDetail>();
        Map<String,String>BoothMap = new Map<String,String>();
        List<SBQQ__QuoteLine__c> qteHistoryList;
        if(Test.isRunningTest()){ 
        qteHistoryList =[SELECT id,Booth__c,Opportunity__c,Opportunity_Name__c,
                                                  (SELECT OldValue,FIELD, NewValue,CreatedBy.Name,createdDate  FROM Histories 
                                                   WHERE FIELD = 'Booth__c' ORDER BY createdDate DESC) FROM SBQQ__QuoteLine__c
                                                  where Commercial_Team__c='Greenbuild' and SBQQ__Quote__r.Quote_Status__c='Approved'
                                                  and SBQQ__Quote__r.SBQQ__Primary__c=true];


        List<Booth__c>boothList =[select id,name from Booth__c where Campaign__r.Commercial_Team__c='Greenbuild'];
        for(Booth__c bth: boothList){
            BoothMap.put(bth.name,bth.Id);
        }

        system.debug('qteHistoryList'+qteHistoryList);
        for(SBQQ__QuoteLine__c qte: qteHistoryList)   {
            BoothChangeDetail btDetail = new BoothChangeDetail();
            for(SBQQ__QuoteLine__History hst:qte.Histories){
                if((String.ValueOf(hst.OldValue)!=null) &&(String.ValueOf(hst.NewValue)!=null)){
                    if((!String.ValueOf(hst.NewValue).StartsWith('a5Q8E'))&&(!String.ValueOf(hst.NewValue).StartsWith('a5Q8E'))){
                        btDetail.oppName=qte.Opportunity_Name__c;
                        btDetail.oppId=qte.Opportunity__c;
                        btDetail.OldValue=String.ValueOf(hst.OldValue);
                        btDetail.NewValue=String.ValueOf(hst.NewValue);
                        btDetail.User =hst.CreatedBy.Name;
                        btDetail.createdDate =hst.createdDate;
                        btDetail.oldValueId =BoothMap.get(String.ValueOf(hst.OldValue));
                        btDetail.newValueId =BoothMap.get(String.ValueOf(hst.NewValue));
                        BoothChangeWrapperList.add(btDetail);   
                    }
                }
            }
        }                               
         }
        return BoothChangeWrapperList;
    }
    Public class BoothChangeDetail {
        @AuraEnabled 
        public String oppName;
        @AuraEnabled 
        public String oppId;
        @AuraEnabled 
        public String oldValue;
        @AuraEnabled 
        public String oldValueId;
        @AuraEnabled 
        public String newValueId;
        @AuraEnabled 
        public String newValue;
        @AuraEnabled 
        public String User;
        @AuraEnabled 
        public DateTime createdDate;
    }
}

This is my Test class

@isTest
public class zTest_BoothChangeReportCtrl {

    public static testMethod void UnitTest_InsertBooth() {
        test.startTest();
        Account acc=new Account(name='testAccount',CurrencyIsoCode='GBP',Country__c='India');
        insert acc;
        Contact con = new Contact(LastName ='Demo',AccountId=acc.Id);
        insert con;
        Pricebook2 pb = new Pricebook2(IsActive = true,name = 'test pricebook',Description='testing',CurrencyIsoCode='GBP');
        insert pb;
        Campaign camp=new Campaign(name='testcampaign1',Type='Digital',Commercial_Team__c='Greenbuild',Order_Service_Area__c='UK',Country__c ='TBD', 
                                   CurrencyIsoCode='GBP',EndDate =System.today(),Price_Book__c =pb.Id,List_Code__c='EVC-4823748271'
                                   ,Admin_Fee_Applied__c =true);
        insert camp;


        Opportunity opp2=new Opportunity(name='test Opp1',CampaignId=camp.Id,AccountId=acc.Id,Type='New',LeadSource='Sales Sourced'
                                         ,Sales_Sourced_Detail__c='Linkedin',CurrencyIsoCode='GBP',StageName='Needs Analysis',Amount=1000
                                         ,Probability=0,Informa_Organization_Code__c='IN05 - IIR US002',ForecastCategoryName='Omitted'
                                         ,CloseDate=System.today(),Payment_Term__c='Full Payment Due - Due Immediately'
                                         ,SPEX_Type__c='Sponsor & Exhibitor',Pricebook2Id =pb.Id,OwnerId =UserInfo.getUserId());
        insert opp2;

        OpportunityContactRole OCR2 = new OpportunityContactRole(OpportunityId=opp2.Id,isPrimary=true,ContactId=con.Id);
        insert OCR2;

        Id SPBID = Test.getStandardPricebookId();
        List<product2> lProd = new List<product2>();
        Product2 product=new Product2(name='DP',CurrencyIsoCode='GBP',ProductCode='ASDF');
        lProd.add(product);
        Product2 prod=new Product2(name='DP1',CurrencyIsoCode='GBP',ProductCode=Label.AdminFeeProductCode);
        lProd.add(prod);
        insert lProd;
        PricebookEntry spbe = new PricebookEntry(Pricebook2Id=SPBID,Product2Id=product.Id,UnitPrice=100,IsActive=true);
        insert spbe;
        PricebookEntry pbe = new PricebookEntry(Pricebook2Id=pb.Id,Product2Id=product.Id,UnitPrice = 100,IsActive=true,CurrencyIsoCode='GBP');
        insert pbe;
        PricebookEntry spbe2 = new PricebookEntry(Pricebook2Id= SPBID,Product2Id=prod.Id,UnitPrice=100,IsActive=true);
        insert spbe2;
        PricebookEntry pbe2 = new PricebookEntry(Pricebook2Id=pb.Id,Product2Id = prod.Id,UnitPrice = 100,IsActive=true,CurrencyIsoCode='GBP');
        insert pbe2;
        opp2.stageName ='Closed Won - Contract In';
        opp2.Probability =100;
        opp2.Primary_Contact_Assigned__c = true;
        opp2.Number_of_Contacts_Roles_Assigned__c = 1;  
        update opp2;
        OpportunityLineItem Opplineitem = new OpportunityLineItem(Event_Name__c=camp.Id,Product2Id=product.Id,Quantity=2,PricebookEntryId=pbe.Id
                                                                 ,Fulfillment_Checkbox__c=true,Fulfillment_Start_Date__c=System.Today()
                                                                  ,Fulfillment_End_Date__c=System.Today().addDays(1),Frequency__c='Monthly'
                                                                 ,Opportunityid=opp2.Id,UnitPrice=0.01,Description='description');  
        insert Opplineitem;
        List<CPQ_Event__c> LCPQEvt = new List<CPQ_Event__c>();

        CPQ_Event__c cloneCampCPQ = new CPQ_Event__c(Campaign__c=camp.Id);
        LCPQEvt.add(cloneCampCPQ);
        insert LCPQEvt;
        Opportunity opp=new Opportunity(name='test Opp1',CampaignId=camp.Id,AccountId=acc.Id
                                        ,Type='New',LeadSource='Sales Sourced',Sales_Sourced_Detail__c='Linkedin',CurrencyIsoCode='GBP'
                                        ,StageName='Needs Analysis',Amount=1000,Probability=0,Informa_Organization_Code__c='IN05 - IIR US002'
                                        ,ForecastCategoryName='Omitted',CloseDate=System.today(),Payment_Term__c='Full Payment Due - Due Immediately'
                                        ,SPEX_Type__c='Sponsor & Exhibitor',Pricebook2Id =pb.Id,OwnerId =UserInfo.getUserId());
        insert opp;
        OpportunityContactRole OCR = new OpportunityContactRole(OpportunityId = opp.Id,isPrimary=true,ContactId=con.Id);
        insert OCR;
        opp.stageName ='Closed Won - Contract In';
        opp.Probability =100;
        opp.Primary_Contact_Assigned__c = true;
        opp.Number_of_Contacts_Roles_Assigned__c = 1;  
        update opp;
         Booth__c booth = new Booth__c(name='123',Campaign__c=camp.Id,Status__c='Available');
        insert booth;
        SBQQ__Quote__c qteOld = new SBQQ__Quote__c(SBQQ__Opportunity2__c =opp.Id,SBQQ__PriceBook__c =opp.Pricebook2Id
                                                   ,SBQQ__PricebookId__c=Opp.PriceBook2Id,SBQQ__Status__c = 'Approved',SBQQ__Primary__c=true
                                                   ,CurrencyIsoCode='GBP',Approval_Reason__c = 'Customer Budget'
                                                   ,Opportunity_Description__c='erf',Opportunity_Instruction__c='test'
                                                   ,Other_Reason__c = 'line item removed',Overall_Discount__c=10,Reason__c='jkljk'
                                                   ,ShowDescription__c=true,OwnerId=opp.ownerid);
        insert qteOld;

        SBQQ__QuoteLine__c qliOld = new SBQQ__QuoteLine__c(SBQQ__ListPrice__c = pbe.UnitPrice,SBQQ__NetPrice__c = pbe.UnitPrice
                                                           ,SBQQ__OriginalPrice__c = pbe.UnitPrice,ListPrice2__c = pbe.UnitPrice
                                                           ,SBQQ__PricebookEntryId__c = pbe.Id,SBQQ__Product__c = product.Id,SBQQ__Quantity__c = 2
                                                           ,SBQQ__Quote__c = qteOld.Id,Mark_Up_Down__c =null,Mark_Up_Down_Amt__c =null
                                                           ,Price_Increment__c =null);
        insert qliOld;
        SBQQ__QuoteLine__c qliOld2 = new SBQQ__QuoteLine__c(SBQQ__ListPrice__c = pbe.UnitPrice,SBQQ__NetPrice__c = pbe.UnitPrice
                                                            ,SBQQ__OriginalPrice__c = pbe.UnitPrice,ListPrice2__c = pbe.UnitPrice
                                                            ,SBQQ__PricebookEntryId__c = pbe.Id,SBQQ__Product__c = product.Id,SBQQ__Quantity__c = 2
                                                            ,SBQQ__Quote__c = qteOld.Id,Mark_Up_Down__c =null,Mark_Up_Down_Amt__c =null
                                                            ,Price_Increment__c =null,SBQQ__RequiredBy__c = qliOld.Id);
        insert qliOld2;

        BoothChangeReportCtrl.getBoothChangeData();
        test.stopTest();  
    } 


}

I am failing to cover test class more than 75%

2

History records aren't created in test contexts, meaning your test will have no records and therefore no coverage.

Depending on the test you might be able to get away with using seeAllData in your test to ensure there are records for your test. If you just need to ensure "yes we have history, yes those fields have values" it's better than not testing the class at all, but not really a solution. For example, if you were writing a custom component to display standard history, but not create or use it, just making sure that your component loads data for different records is "good enough".

So you either have to "fake it" by providing hand created records via JSON or Test.LoadData. Problem with this approach is that newValue and oldValue are not writeable by any context, so you can't really test your records, just ensure that you have records.

A "perfect" solution is to use a wrapper class over your history records. You'll need a "provider" to load in records to your wrappers, which you can test in a class with seeAllData or loaded data. Then, in your actual code, you can create records & test their behavior & use the OldValue/NewValue fields.


Related reading:

Is it possible to test apex that relies on field history tracking?

This specific answer: Is it possible to test apex that relies on field history tracking?

Deserialize History record with read-only fields?

When should I use SeeAllData=true in my test methods?

Not the answer you're looking for? Browse other questions tagged or ask your own question.