+ Start a Discussion
anjaanja 

help with test coverage

http://wiki.developerforce.com/page/Sorting_Tables - this is some code developed by someone else - I found it online - I made very few changes and cannot get more that 61% coverage (with this or original) - it is failing at lines 17,18,21,22,23,42,43,46,47,49,50,52,74,75,77,78

 

I am not sure what to add to the tests in order to get the coverage up:

 

 

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));

            }

           

            // DevAngel - EDIT - Because you may not have a value for the reference field in the first record

            // in the table you are sorting, this approach will fail on the substring method.  Below is

            // is a more reliable method using describe calls

            /*

            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;

                }

            }

            */

 

            // DevAngel - EDIT - New approach...

            List<Schema.Sobjecttype> objType = items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getReferenceTo();

            String objectType = objType[0].getDescribe().getName();

 

            //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 )){

                // DevAngel - EDIT - if the reference field is null then we will not have a result, so we need to "create one"

                if (s.get('Name') == null) {

                    referenceName.put((Id)s.get('Id'), 'n/a');

                } else {

                    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<Account> accs = new List<Account>();

        for(integer i = 0; i<1000; i++){

            accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));

        }

       

        Test.startTest();

        Long start = system.currentTimeMillis();

        sortList(accs,'Annualized_Revenue__c','asc');

        system.debug(system.currentTimeMillis() - start);

        Test.stopTest();

       

        //Assert the list was sorted correctly

        Decimal assertValue = -1;

        for(Account a : accs) {

            System.debug('Acc value: ' + a.Annualized_Revenue__c);

            System.assert(assertValue <= a.Annualized_Revenue__c);

            assertValue = a.Annualized_Revenue__c;

        } 

    }

  

   

public static testMethod void sortDescendingTest(){

       

       

        List<Account> accs = new List<Account>();

        for(integer i = 0; i<1000; i++){

            accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));

        }

       

        Test.startTest();

        sortList(accs,'Annualized_Revenue__c','desc');

        Test.stopTest();

       

        //Assert the list was sorted correctly

        Decimal assertValue = 1001;

        for(Account a : accs) {

            System.debug('Opp value: ' + a.Annualized_Revenue__c);

            System.assert(assertValue >= a.Annualized_Revenue__c);

            assertValue = a.Annualized_Revenue__c;

        } 

    }

}

 

 

Best Answer chosen by Admin (Salesforce Developers) 
anjaanja

Here is what I finally worked out:

 

public with sharing class tableSort
{

List<Account> accs;
public String sortField {get; set;}
public String previousSortField {get; set;}

public List<Account> getaccs()
{
if(accs == null){
accs = [select Id, Name, BillingCity, BillingState, VSA_Name__c, Divisions__c, Verification_Date__c from Account where RecordTypeID = '01250000000DQkZ'limit 1000];
}
return accs;
}

public void doSort()
{
String order = 'asc';

/*This checks to see if the same header was clicked two times in a row, if so
it switches the order.*/
if(previousSortField == sortField)
{
order = 'desc';
previousSortField = null;
}else
{
previousSortField = sortField;
}

//To sort the table we simply need to use this one line, nice!
superSort.sortList(accs,sortField,order);
}


public static testMethod void TableSortTest()
{
Account a = new Account(name='Test');
insert a;
List<Account> Accounts = new List<Account>
{
new Account(Name='Phoenix',BillingCity='San Jose', BillingState='CA', VSA_Name__c='San Jose', Divisions__c='San Jose'),
new Account(Name='Seguin',BillingCity='Cupertino')
};

insert Accounts;

Test.setCurrentPage(Page.sortabletabletemplate); // Replace with your page's name.

Test.startTest();

ApexPages.currentPage().getParameters().put('id',a.id);
tableSort controller = new tableSort();

System.assertEquals(1000,controller.getaccs().size());
controller.sortField = 'Name';
controller.doSort();

System.assertEquals('Phoenix',controller.getaccs()[0].BillingCity);
controller.doSort();

System.assertEquals('Seguin',controller.getaccs()[0].BillingCity);
controller.sortField='Verification_Date__c';
controller.doSort();

Test.stopTest();
}
}

 

 

 

 

Here is the superSort Class:

 

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));
}

// DevAngel - EDIT - Because you may not have a value for the reference field in the first record
// in the table you are sorting, this approach will fail on the substring method. Below is
// is a more reliable method using describe calls
/*
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;
}
}
*/

// DevAngel - EDIT - New approach...
List<Schema.Sobjecttype> objType = items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getReferenceTo();
String objectType = objType[0].getDescribe().getName();

//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 )){
// DevAngel - EDIT - if the reference field is null then we will not have a result, so we need to "create one"
if (s.get('Name') == null) {
referenceName.put((Id)s.get('Id'), 'n/a');
} else {
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() {
Id Owner;

List<Account> accs = new List<Account>();
Owner = [SELECT id FROM User LIMIT 1].id;

for(integer i = 0; i<1000; i++) {
Account a = new Account();
a.Name='Test' + i;
a.AnnualRevenue=1000 * Math.random();
a.OwnerId = Owner;
accs.add(a);
}

// accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));

Test.startTest();
Long start = system.currentTimeMillis();
sortList(accs,'OwnerId','asc');
system.debug(system.currentTimeMillis() - start);
Test.stopTest();

//Assert the list was sorted correctly


}

}

All Answers

anjaanja

the main problem is with "referenceName" - cannot think of how to add this to test

anjaanja

Here is what I finally worked out:

 

public with sharing class tableSort
{

List<Account> accs;
public String sortField {get; set;}
public String previousSortField {get; set;}

public List<Account> getaccs()
{
if(accs == null){
accs = [select Id, Name, BillingCity, BillingState, VSA_Name__c, Divisions__c, Verification_Date__c from Account where RecordTypeID = '01250000000DQkZ'limit 1000];
}
return accs;
}

public void doSort()
{
String order = 'asc';

/*This checks to see if the same header was clicked two times in a row, if so
it switches the order.*/
if(previousSortField == sortField)
{
order = 'desc';
previousSortField = null;
}else
{
previousSortField = sortField;
}

//To sort the table we simply need to use this one line, nice!
superSort.sortList(accs,sortField,order);
}


public static testMethod void TableSortTest()
{
Account a = new Account(name='Test');
insert a;
List<Account> Accounts = new List<Account>
{
new Account(Name='Phoenix',BillingCity='San Jose', BillingState='CA', VSA_Name__c='San Jose', Divisions__c='San Jose'),
new Account(Name='Seguin',BillingCity='Cupertino')
};

insert Accounts;

Test.setCurrentPage(Page.sortabletabletemplate); // Replace with your page's name.

Test.startTest();

ApexPages.currentPage().getParameters().put('id',a.id);
tableSort controller = new tableSort();

System.assertEquals(1000,controller.getaccs().size());
controller.sortField = 'Name';
controller.doSort();

System.assertEquals('Phoenix',controller.getaccs()[0].BillingCity);
controller.doSort();

System.assertEquals('Seguin',controller.getaccs()[0].BillingCity);
controller.sortField='Verification_Date__c';
controller.doSort();

Test.stopTest();
}
}

 

 

 

 

Here is the superSort Class:

 

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));
}

// DevAngel - EDIT - Because you may not have a value for the reference field in the first record
// in the table you are sorting, this approach will fail on the substring method. Below is
// is a more reliable method using describe calls
/*
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;
}
}
*/

// DevAngel - EDIT - New approach...
List<Schema.Sobjecttype> objType = items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getReferenceTo();
String objectType = objType[0].getDescribe().getName();

//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 )){
// DevAngel - EDIT - if the reference field is null then we will not have a result, so we need to "create one"
if (s.get('Name') == null) {
referenceName.put((Id)s.get('Id'), 'n/a');
} else {
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() {
Id Owner;

List<Account> accs = new List<Account>();
Owner = [SELECT id FROM User LIMIT 1].id;

for(integer i = 0; i<1000; i++) {
Account a = new Account();
a.Name='Test' + i;
a.AnnualRevenue=1000 * Math.random();
a.OwnerId = Owner;
accs.add(a);
}

// accs.add(new Account(Name = 'test' + i, Annualized_Revenue__c = 1000 * Math.random()));

Test.startTest();
Long start = system.currentTimeMillis();
sortList(accs,'OwnerId','asc');
system.debug(system.currentTimeMillis() - start);
Test.stopTest();

//Assert the list was sorted correctly


}

}

This was selected as the best answer