function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
KatherineCKatherineC 

Code Coverage is 71% in Sandbox, but when deployed it says only 19%?

We recently upgraded from trial to paid production environment, tried to remove unwanted triggers and start from scratch. I noticed that Chatter has a trigger only has 35% coverage, it affects my overall coverage, what can I do with that? It's also confusing that we have 71% overall code coverage in Sandbox, but when deployed it said only 19%, how come? Attached are screenshots:
sandbox coverage
Sandbox Overall Coverage


User-added image
Production Overall Coverage


User-added image
Error Msg

KatherineCKatherineC
I just run those on eclipse and notice these, Chatter, trial customer portal are not created by us, it's by salesforce, how can we make changes.


 User-added image
Deepak Kumar ShyoranDeepak Kumar Shyoran
First please improve the Code coverage for the Chatter_Answer_Question class and make sure you are not using Org Data in test class by using (seeAllData= true) create Data in Test class and don't use (seeAllData = true).
As Chatter_Answer_Question have 17 line so if able to improve code coverage between 85%-90% then it will improve the overall code coverage for you production. So improve code coverage for Chatter_Answer_Question in Sandbox and then deploy it with other components.
KatherineCKatherineC
Oh no, I'm new to coding. Deepak, could you please help me improve the Test Class? 

@isTest
private class ChatterAnswersEscalationTriggerTest {
static testMethod void validateQuestionEscalation() {
  String questionTitle = 'questionTitle';
  String questionBody = 'questionBody';
  Community[] c = [SELECT Id from Community];
  // We cannot create a question without a community
  if (c.size() == 0) { return; }
  String communityId = c[0].Id;
  Question q = new Question();
  q.Title = questionTitle;
  q.Body = questionBody;
  q.CommunityId = communityId;
  insert(q);
  q.Priority = 'high';
  update(q);
  Case ca = [SELECT Origin, CommunityId, Subject, Description from Case where QuestionId =: q.Id];
  // Test that escaltion trigger correctly escalate the question to a case
  System.assertEquals(questionTitle, ca.Subject);
  System.assertEquals(questionBody, ca.Description);
  System.assertEquals('Chatter Answers', ca.Origin);
  System.assertEquals(communityId, ca.CommunityId);
}
}
Deepak Kumar ShyoranDeepak Kumar Shyoran
Yes I can but where is the Apex Class for which this test is ?
KatherineCKatherineC
Thank you so much. Here are the info:

TRIGGER

trigger chatter_answers_question_escalation_to_case_trigger on Question (after update) {
    for (Question q: Trigger.new) {
        try {
            if (q.Priority == 'high' && (q.Cases == null || q.Cases.size() == 0) && Trigger.oldMap.get(q.id).Priority != 'high') {
                q = [select Id, Title, Body, CommunityId, createdById, createdBy.AccountId, createdBy.ContactId from Question where Id = :q.Id];
                Case newCase = new Case(Origin='Chatter Answers', OwnerId=q.CreatedById, QuestionId=q.Id, CommunityId=q.CommunityId, Subject=q.Title, Description=q.Body, AccountId=q.CreatedBy.AccountId, ContactId=q.CreatedBy.ContactId);
                insert newCase;
            }
        } catch (Exception e) {
            String subjectText = 'Case Escalation exception in site ' + Site.getName();
            String bodyText = 'Case Escalation on Question having ID: ' + q.Id + ' has failed with the following message: ' + e.getMessage() +
                '\n\nStacktrace: ' + e.getStacktraceString();

            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddresses = new String[] { Site.getAdminEmail() };

            mail.setReplyTo('no-reply@salesforce.com');
            mail.setSenderDisplayName('Salesforce Chatter Answers User');

            // The default sender is the portal user causing this trigger to run, to change this, set an organization-wide address for
            // the portal user profile, and set the ID in the following line.
            // mail.setOrgWideEmailAddressId(orgWideEmailAddressId);
            mail.setToAddresses(toAddresses);
            mail.setSubject(subjectText);
            mail.setPlainTextBody(bodyText);
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        }
    }
}

APEX CLASS - TOTAL 4

public class ChatterAnswers {
    public String createAccount(String firstname, String lastname, Id siteAdminId) {
         Account a = new Account(name = firstname + ' ' + lastname, ownerId = siteAdminId);
         insert a;
         return a.Id;
    }
}
-------------------------------------------------------------------------------

@isTest
private class ChatterAnswersEscalationTriggerTest {
  static testMethod void validateQuestionEscalation() {
    String questionTitle = 'questionTitle';
    String questionBody = 'questionBody';
    Community[] c = [SELECT Id from Community];
    // We cannot create a question without a community
    if (c.size() == 0) { return; }
    String communityId = c[0].Id;
    Question q = new Question();
    q.Title = questionTitle;
    q.Body = questionBody;
    q.CommunityId = communityId;
    insert(q);
    q.Priority = 'high';
    update(q);
    Case ca = [SELECT Origin, CommunityId, Subject, Description from Case where QuestionId =: q.Id];
    // Test that escaltion trigger correctly escalate the question to a case
    System.assertEquals(questionTitle, ca.Subject);
    System.assertEquals(questionBody, ca.Description);
    System.assertEquals('Chatter Answers', ca.Origin);
    System.assertEquals(communityId, ca.CommunityId);
  }
}

---------------------------------------------------------------------------------------------
public class TrialCustomerPortalHomePageController {
  
   User loggedInUser = [Select id,contactId,Contact.AccountId from User where id = :UserInfo.getUserId()];
  
   public List<Asset> MyRegisteredProducts {get; set;}
   public List<Case> MyRecentCases {get; set;}
   public List<Solution> TopSolutions {get; set;}
   public List<Idea> PopularIdeas {get; set;}
  
   public String sortField1 {get; set;}
   public String previousSortField1 {get; set;}
   public String sortField2 {get; set;}
   public String previousSortField2 {get; set;}
   public String sortField3 {get; set;}
   public String previousSortField3 {get; set;}
   public String sortField4 {get; set;}
   public String previousSortField4 {get; set;}
           
   public TrialCustomerPortalHomePageController() {
        MyRegisteredProducts = [select id,Name,SerialNumber,InstallDate,UsageEndDate,Status
                                from Asset
                                where ContactId = :loggedInUser.ContactId
                                order by SerialNumber desc limit 3];
       
        MyRecentCases = [select id,CaseNumber,Subject,Status,LastModifiedDate
                         from Case
                         where ContactId = :loggedInUser.ContactId
                         order by LastModifiedDate desc limit 3];
       
        TopSolutions = [select id,SolutionName,TimesUsed,LastModifiedDate
                        from Solution
                        order by TimesUsed desc limit 3];
                             
        PopularIdeas = [select id,Title,Categories,VoteTotal
                        from Idea
                        order by VoteTotal desc limit 3];
   }
  
   public void SortProducts(){
        String order = 'asc';
        if(previousSortField1 == sortField1){
            order = 'desc';
            previousSortField1 = null;
        }else{
            previousSortField1 = sortField1;
        }
        superSort.sortList(MyRegisteredProducts,sortField1,order);
    }
    public void SortCases(){
        String order = 'asc';
        if(previousSortField2 == sortField2){
            order = 'desc';
            previousSortField2 = null;
        }else{
            previousSortField2 = sortField2;
        }
        superSort.sortList(MyRecentCases,sortField2,order);
    }
    public void SortSolutions(){
        String order = 'asc';
        if(previousSortField3 == sortField3){
            order = 'desc';
            previousSortField3 = null;
        }else{
            previousSortField3 = sortField3;
        }
        superSort.sortList(TopSolutions,sortField3,order);
    }
    public void SortIdeas(){
        String order = 'asc';
        if(previousSortField4 == sortField4){
            order = 'desc';
            previousSortField4 = null;
        }else{
            previousSortField4 = sortField4;
        }
        superSort.sortList(PopularIdeas,sortField4,order);
    }
   
}

----------------------------------------NOT SURE THIS ONE IS CHATTER RELATED OR NOT-------------
public class superSort {

    /*This method takes 3 arguments, the List of objects to sort, the field to sort,
    and the order, asc or desc*/
   
    public static void sortList(List<sObject> items, String sortField, String order){
        /*I must give credit where it is due as the sorting algorithm I am using is the
        one supplied by Andrew Waite here: http://blog.sforce.com/sforce/2008/09/sorting-collect.html */
       
        Boolean isSortFieldReference = false;
        Map<Id,String> referenceName;
        
        /*Determine the type of the field that needs to be sorted, if it is a
        reference we will want sort by the name of the related object, not the
        ID itself*/
        if(items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getType().Name() == 'REFERENCE'){
            isSortFieldReference = true;
            referenceName = new Map<Id,String>();
           
            /*Determine the type of this object and populate the Id to Name map*/
            Set<Id> referenceIds = new Set<Id>();
            for(sObject s : items){
               referenceIds.add((Id)s.get(sortField));
            }
           
            String objectID = (String)items[0].get(sortField);
            String prefix = objectID.substring(0,3);
            String objectType;
            Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
            for(Schema.SObjectType s : gd.values()){
                if(prefix == s.getDescribe().getKeyPrefix()){
                    objectType = s.getDescribe().Name;
                }
            }
           
            //Query the related objects for the name and populate the Id -> Name map
            String queryString = 'select Id, Name from ' + objectType + ' where ID IN :referenceIDs';
            for(sObject s : Database.query(queryString )){
                referenceName.put((Id)s.get('Id'),(String)s.get('Name'));
            }
        }
               
        /*Declare a list that will contain the sorted results. I think this is one of the
        coolest parts of this method as the system will not let you declare a list of
        sObjects (List<sObject> objects = new List<sObjects>();) but using a
        wrapper class you can bypass this system limitation to create this type of list */
        List<cObject> resultList = new List<cObject>();
   
        //Create a map that can be used for sorting
        Map<object, List<cObject>> objectMap = new Map<object, List<cObject>>();
       
        for(sObject ob : items){
            if(isSortFieldReference == false){
                if(objectMap.get(ob.get(sortField)) == null){
                    objectMap.put(ob.get(sortField), new List<cObject>());
                }
                cObject o = new cObject(ob);
                objectMap.get(ob.get(sortField)).add(o);
            }else{
                if(objectMap.get(referenceName.get((Id)ob.get(sortField))) == null){
                    objectMap.put(referenceName.get((Id)ob.get(sortField)), new List<cObject>());
                }
                cObject o = new cObject(ob);
                objectMap.get(referenceName.get((Id)ob.get(sortField))).add(o);
            }
        }
       
        //Sort the keys
        List<object> keys = new List<object>(objectMap.keySet());
        keys.sort();
       
        for(object key : keys){
            resultList.addAll(objectMap.get(key));
        }
       
        //Apply the sorted values to the source list
        items.clear();
        if(order.toLowerCase() == 'asc'){
            for(cObject ob : resultList){
                items.add(ob.obj); 
            }
        }else if(order.toLowerCase() == 'desc'){
            for(integer i = resultList.size()-1; i >= 0; i--){
                items.add(resultList[i].obj);  
            }
        }
    }
   
    public class cObject{
        sObject obj {get; set;}
       
        public cObject(sObject obj){
            this.obj = obj;
        }
    }
   
    /*Some test methods that provide 100% coverage
    public static testMethod void sortAscendingTest(){
       
        List<Opportunity> opps = new List<Opportunity>();
        for(integer i = 0; i<1000; i++){
            opps.add(new Opportunity(Name = 'test' + i, Amount = 1000 * Math.random()));
        }
       
        Test.startTest();
        Long start = system.currentTimeMillis();
        sortList(opps,'Amount','asc');
        system.debug(system.currentTimeMillis() - start);
        Test.stopTest();
       
        //Assert the list was sorted correctly
        Decimal assertValue = -1;
        for(Opportunity o : opps) {
            System.debug('Opp value: ' + o.amount);
            System.assert(assertValue <= o.amount);
            assertValue = o.amount;
        } 
    }
   
    public static testMethod void sortDescendingTest(){
       
        List<Opportunity> opps = new List<Opportunity>();
        for(integer i = 0; i<1000; i++){
            opps.add(new Opportunity(Name = 'test' + i, Amount = 1000 * Math.random()));
        }
       
        Test.startTest();
        sortList(opps,'Amount','desc');
        Test.stopTest();
       
        //Assert the list was sorted correctly
        Decimal assertValue = 1001;
        for(Opportunity o : opps) {
            System.debug('Opp value: ' + o.amount);
            System.assert(assertValue >= o.amount);
            assertValue = o.amount;
        } 
    }*/
}
MichaelSFDCMichaelSFDC
@KatherineC did you ever resolve this? I'm having the same issue. 

KatherineCKatherineC
Yes, we have premier account, so salesforce fix chatter, trial customer portal and superfort test classes to increase coverage then I deploy my triggers successfully. If you have standard account service they won't fix it and will refer you to developer forum only.
MichaelSFDCMichaelSFDC
Thanks for your reply. I just escalatated my case. So far all I got from support was I need to increase coverage. We have Premier +Admin. I'm getting the runaround so far.