+ Start a Discussion
ismyhcismyhc 

Moving Apex Classes from api 22 to api 25 breaks my tests :(

So I've just started to work on an app that I wrote a year ago, which was using the api version 22. I havent touched this app in quite sometime, but we are now wanting to use it and there are some modifications that I need to make. I ran my tests and got 76% coverage. Well I thought it maybe a good idea to update the api version from 22 to the latest at 25. 

 

Heres what I get. I can update all classes and triggers except test class to 25 with no problems. When I update my test class to api version 24 or above I get:

 

4 errors of:

 

System.NullPointerException: Attempt to de-reference a null object

 

Stack traces for each of the above errors are:

Class.aiMatch.aimatchEditSettingsController.getApiUrlValue: line 10, column 1 Class.aiMatch.testaimatchOpportunityGrab.testEditSettingsControllerPos: line 106, column 1

 

 

Class.aiMatch.aimatchXmlApiCall.buildWebServiceRequest: line 10, column 1 Class.aiMatch.testaimatchOpportunityGrab.testXmlApiCall: line 44, column 1

 

Class.aiMatch.aimatchGetAdvertisersXmlApiCall.buildWebServiceRequest: line 17, column 1 Class.aiMatch.testaimatchOpportunityGrab.testGetAdvertisersXmlApiCall: line 63, column 1

 

 

Class.aiMatch.aimatchEditSettingsController.getApiUrlValue: line 10, column 1 Class.aiMatch.testaimatchOpportunityGrab.testEditSettingsControllerNeg: line 147, column 1

 

1 error of:

 

System.DmlException: Update failed. First exception on row 0 with id 006U0000007zk5DIAQ; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, aiMatch.aimatchOpportunityGrabTrigger: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.aiMatch.aimatchOpportunityGrabTrigger: line 22, column 1: []

 

Stack trace of above error:

Class.aiMatch.testaimatchOpportunityGrab.aimatchOpportunityGrabTest: line 25, column 1

 

 

 

The app works as expected. I've just gotten back into working with Apex after a year or so. Been working on Ruby and Javascript projects all year so I quite a bit rusty... :(

 

Any help is much appreciated!

 

 Here is my test class:

 

public class testaimatchOpportunityGrab {

    private static testmethod void aimatchOpportunityGrabTest() {
        
        Profile p = [select id from profile where name='System Administrator']; 
        User u = new User(alias = 'standt', email='sysadmin@testorg.com', 
            emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US', 
            localesidkey='en_US', profileid = p.Id, 
            timezonesidkey='America/Los_Angeles', username='aimatchtest@testorg.com');


        System.runAs(u) {
            
            List<Opportunity> listOpportunity = new List<Opportunity>();
                    
            // Create Opportunity test data
            Opportunity o = new Opportunity (name = 'test', campaign_created_in_aimatch__c = true, ownerid = '005U0000000gvRnIAI',
                                                        stagename = 'Renew', closedate = system.today(), aimatch_advertiser__c = 'a00U00000016hLW',
                                                        campaign_start_date__c = Date.today(), campaign_end_date__c = Date.today() + 30);
            insert o;                                                                                                  
            
            test.startTest();
            listOpportunity.add(o);
            
            update listOpportunity;


            test.stopTest();    
        
        }

    }    
    
    private static testMethod void testXmlApiCall() {
        //First, build the http request
        aimatchXmlApiCall testWebCallout = new aimatchXmlApiCall();
        String campName = 'Testcamp';
        String ownerName = 'testMe';
        String ownerEmail = 'test@email.com';
        String advertiserID = '12';
        String sDate = '2011-02-08';
        String eDate = '2011-02-09';
        
        HttpRequest req = testWebCallout.buildWebServiceRequest(campName, ownerName, ownerEmail, advertiserID, sDate, eDate);
   
        //NOTE - WE DO NOT EXECUTE THE METHOD, invokeWebService.  
        //Now, since we can't execute the actual web service, 
        //write apex code to build a sample HttpResponse object
      
        String xmlRes = '<advertisers type="array"><advertiser><id type="integer">7</id><name>ABC Telecom</name></advertiser></advertisers>';
      
        HttpResponse res = new HttpResponse();
        res.setBody(xmlRes);
        
        //Apply test data and attributes to the HttpResponse object as needed
        testWebCallout.handleWebServiceResponse(res, ownerEmail);
  
    }

    private static testMethod void testGetAdvertisersXmlApiCall() {
      //First, build the http request
        aimatchGetAdvertisersXmlApiCall testWebCallout  = new aimatchGetAdvertisersXmlApiCall();
        HttpRequest req = testWebCallout.buildWebServiceRequest();
   
      //NOTE - WE DO NOT EXECUTE THE METHOD, invokeWebService.       
      //Now, since we can't execute the actual web service, 
      //write apex code to build a sample HttpResponse object
      
      String xmlRes = '<advertisers type="array"><advertiser><id type="integer">7</id><name>ABC Telecom</name></advertiser></advertisers>';
      
      HttpResponse res = new HttpResponse();
      res.setBody(xmlRes);
      
      //Apply test data and attributes to the HttpResponse object as needed
      testWebCallout.handleWebServiceResponse(res);
  
    }

    private static testmethod void testEditSettingsControllerPos() {
        
        Profile p = [select id from profile where name='System Administrator']; 
        User u = new User(alias = 'standt', email='sysadmin@testorg.com', 
            emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US', 
            localesidkey='en_US', profileid = p.Id, 
            timezonesidkey='America/Los_Angeles', username='aimatchtest@testorg.com');
            
            list<aimatch_conf__c> theConf = [select id, name from aimatch_conf__c where name = 'settings' limit 1];
            list<aimatch_conf__c> updateConf = new list<aimatch_conf__c>();
            
            for(aimatch_conf__c con : theConf) {

                aimatch_conf__c thisConfVal = new aimatch_conf__c(Id=con.id);
                
                thisConfVal.name = 'settings';
                thisConfVal.aimatch_api_url__c = 'http://url.com';
                thisConfVal.aimatch_api_key__c = '123424351';
                thisConfVal.aimatch_schedule__c = '0 56 10 * * ?';
                thisConfVal.campaign_start_date_field_name__c = 'campaign_Start_Date__c';
                thisConfVal.campaign_end_date_field_name__c = 'campaign_End_Date__c';
                updateConf.add(thisConfVal);
            }
            upsert updateConf;

        System.runAs(u) {
                        
            aimatchEditSettingsController.getApiUrlValue();
            aimatchEditSettingsController.getApiKeyValue();
            aimatchEditSettingsController.getAdvSchValue();
            aimatchEditSettingsController.getCampStartDateFieldNameValue();
            aimatchEditSettingsController.getCampEndDateFieldNameValue();
            
            aimatchEditSettingsController editSettingsController = new aimatchEditSettingsController();
            editSettingsController.schAdv();
            editSettingsController.save();
        
        }
            
    }

    private static testmethod void testEditSettingsControllerNeg() {
        
        Profile p = [select id from profile where name='System Administrator']; 
        User u = new User(alias = 'standt', email='sysadmin@testorg.com', 
            emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US', 
            localesidkey='en_US', profileid = p.Id, 
            timezonesidkey='America/Los_Angeles', username='aimatchtest@testorg.com');
            
            list<aimatch_conf__c> theConf = [select id, name from aimatch_conf__c where name = 'settings' limit 1];
            list<aimatch_conf__c> updateConf = new list<aimatch_conf__c>();
            
            for(aimatch_conf__c con : theConf) {

                aimatch_conf__c thisConfVal = new aimatch_conf__c(Id=con.id);
                
                thisConfVal.name = 'settings';
                thisConfVal.aimatch_api_url__c = '';
                thisConfVal.aimatch_api_key__c = '';
                thisConfVal.aimatch_schedule__c = '';
                thisConfVal.campaign_start_date_field_name__c = '';
                thisConfVal.campaign_end_date_field_name__c = '';
                updateConf.add(thisConfVal);
            }
            upsert updateConf;

        System.runAs(u) {
            
            aimatchEditSettingsController.getApiUrlValue();
            aimatchEditSettingsController.getApiKeyValue();
            aimatchEditSettingsController.getAdvSchValue();
            aimatchEditSettingsController.getCampStartDateFieldNameValue();
            aimatchEditSettingsController.getCampEndDateFieldNameValue();
            
            aimatchEditSettingsController editSettingsController = new aimatchEditSettingsController();
            editSettingsController.schAdv();
            editSettingsController.save();
        
        }
    }
     
}

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
Damien_Damien_

When you are moving from a lower version to another (I can't remember the exact version number but I'll guess 24 according to your problem) it forces you to create your own test data in the class.  You can't use existing data in the System with that.

 

So, in order to fix this, you need to create your test data in the test class and not expect certain data to exist already.

All Answers

Damien_Damien_

When you are moving from a lower version to another (I can't remember the exact version number but I'll guess 24 according to your problem) it forces you to create your own test data in the class.  You can't use existing data in the System with that.

 

So, in order to fix this, you need to create your test data in the test class and not expect certain data to exist already.

This was selected as the best answer
ismyhcismyhc

Hmm... Okay. I thought I was doing this...

 

For instance..

private static testmethod void testEditSettingsControllerPos() {
    
    Profile p = [select id from profile where name='System Administrator']; 
    User u = new User(alias = 'standt', email='sysadmin@testorg.com', 
        emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US', 
        localesidkey='en_US', profileid = p.Id, 
        timezonesidkey='America/Los_Angeles', username='aimatchtest@testorg.com');
        
        list<aimatch_conf__c> theConf = [select id, name from aimatch_conf__c where name = 'settings' limit 1];
        list<aimatch_conf__c> updateConf = new list<aimatch_conf__c>();
        
        for(aimatch_conf__c con : theConf) { <--- creating settings here in this loop

            aimatch_conf__c thisConfVal = new aimatch_conf__c(Id=con.id);
            
            thisConfVal.name = 'settings';
            thisConfVal.aimatch_api_url__c = 'http://url.com';
            thisConfVal.aimatch_api_key__c = '123424351';
            thisConfVal.aimatch_schedule__c = '0 56 10 * * ?';
            thisConfVal.campaign_start_date_field_name__c = 'campaign_Start_Date__c';
            thisConfVal.campaign_end_date_field_name__c = 'campaign_End_Date__c';
            updateConf.add(thisConfVal);
        }
        upsert updateConf;

    System.runAs(u) {
                    
        aimatchEditSettingsController.getApiUrlValue();  <-- is it because these calls are directly to the methods and not test method versions?
        aimatchEditSettingsController.getApiKeyValue();
        aimatchEditSettingsController.getAdvSchValue();
        aimatchEditSettingsController.getCampStartDateFieldNameValue();
        aimatchEditSettingsController.getCampEndDateFieldNameValue();
        
        aimatchEditSettingsController editSettingsController = new aimatchEditSettingsController();
        editSettingsController.schAdv();
        editSettingsController.save();
    
    }
        
}

 

Im creating test data in the loop, but I am assuming the issue is that I am calling the actuall methods instead of test versions of the methods?

 

Just want to make sure I understand correctly here..  So I need to make seperate test methods for each of those and call them instead of the actuall production methods..?

 

Man.. maybe I should stay on api 22!

 

Thanks for you help!

Damien_Damien_

I don't think you actually do.  Your first line here:

list<aimatch_conf__c> theConf = [select id, name from aimatch_conf__c where name = 'settings' limit 1];

Queries for existing data.  It then loops through that data and creates additional related data.  The problem you have, is that the loop never gets fired because your first query brings back 0 records.  Therefore you have no data to work with.

ismyhcismyhc

Yeap, you are right. After debugging there is no data.

 

I guess I was doing this wrong all to begin with.. What am I doing wrong here?

 

list<aimatch_conf__c> theConf = [select id, name from aimatch_conf__c where name = 'settings' limit 1];
list<aimatch_conf__c> updateConf = new list<aimatch_conf__c>();

for(aimatch_conf__c con : theConf) {

    aimatch_conf__c thisConfVal = new aimatch_conf__c(Id=con.id);
    
    thisConfVal.name = 'settings';
    thisConfVal.aimatch_api_url__c = 'http://url.com';
    thisConfVal.aimatch_api_key__c = '123424351';
    thisConfVal.aimatch_schedule__c = '0 56 10 * * ?';
    thisConfVal.campaign_start_date_field_name__c = 'campaign_Start_Date__c';
    thisConfVal.campaign_end_date_field_name__c = 'campaign_End_Date__c';
    updateConf.add(thisConfVal);
}
upsert updateConf;

 

Id like to be able to query this as if it where a conf from my methods that I call later on.

 

Once again, thanks for any insight.

Damien_Damien_

Create this object instead of querying for it:

 

aimatch_conf__c
ismyhcismyhc

Thanks again!

 

Hopefully I can work through the other issues without bothering you the community much more!

 

This is how I ended up doing it.

 

private static testmethod void testEditSettingsControllerNeg() {
    
    Profile p = [select id from profile where name='System Administrator']; 
    User u = new User(alias = 'standt', email='sysadmin@testorg.com', 
        emailencodingkey='UTF-8', lastname='Testing', languagelocalekey='en_US', 
        localesidkey='en_US', profileid = p.Id, 
        timezonesidkey='America/Los_Angeles', username='aimatchtest@testorg.com');
        
    List<aimatch_conf__c> conf = new List<aimatch_conf__c>();
                
    // Create Opportunity test data
    aimatch_conf__c c = new aimatch_conf__c (name = 'settings', aimatch_api_url__c = '', aimatch_api_key__c = '',
                                             aimatch_schedule__c = '', campaign_start_date_field_name__c = '',
                                             campaign_end_date_field_name__c = '');
    insert c;            

    System.runAs(u) {
        
        aimatchEditSettingsController.getApiUrlValue();
        aimatchEditSettingsController.getApiKeyValue();
        aimatchEditSettingsController.getAdvSchValue();
        aimatchEditSettingsController.getCampStartDateFieldNameValue();
        aimatchEditSettingsController.getCampEndDateFieldNameValue();
        
        aimatchEditSettingsController editSettingsController = new aimatchEditSettingsController();
        editSettingsController.schAdv();
        editSettingsController.save();
    
    }
}

 

kibitzerkibitzer

You can always set the seealldata attribute on your tests to True. That restores the previous behavior.

 

If your test code is already written to work correctly with data on an org, there's no particular reason not to keep it working that way.

 

Dan

 

Damien_Damien_

Typically its very bad practice to set the seealldata attribute to true.  Never use it unless you absolutely MUST or it will cause you to miss a deadline.

ismyhcismyhc

Yeah, I had actually found that option yesterday and while it does work and could be used in a pinch, I wanted to try and write the tests correctly with their own test data.

kibitzerkibitzer

No - actually, I disagree with that statement.

 

Remember, seealldata has been true up until very recently. It's still required in a number of situations where you must use data that can't be set up at test time.

 

The reason seealldata=false is currently the default is twofold.

1. It does make things easier on developers. It enforces the recommendation that you create your own test data and reduces the chances of bugs caused by existing data. It simplifies package development by eliminating the need to reintialize configuration data each time (i.e. the difference between an initial install and an update).

2. It does impose a lighter load on the platform.

 

However, seealldata=false also has a major disadvantage. It eliminates detection of non-selective SOQL queries in larger organizations. Those only appear where querying against large data sets. So, in fact, there is a case to be made that you should use seealldata=true in some of your tests specifically to test for this situation.

 

So, in fact, if you have test code that was designed for an earlier API and is working correctly, it is basically a waste of time and money to rewrite it to use seealldata=false. Best practice in this situation is to try your test classes, and then set seealldata=true to those that need it.

 

Always be careful when interpreting best practices as defined in the documentation. You always have to interpret it in the context of your particular situation. The fact that seealldata=false is the default and is recommended for new test code does not mean it is best for existing test code.