+ Start a Discussion
MedhanieHabteMedhanieHabte 

Test Classes Not Passing - Null pointer exception - Superbadge Data Integration Specialist (Part 3)

Hi all, I seem to be stuck on authoring the class and test classes on the Superbadge Data Integration Specialist. I have authored the ProjectCalloutService plus the test class and HTTPCallouts, but encounter a Null pointer exception error at line 35:1

Anything I should add to the code. I have built the process builder as needed.

Project Callout Service
public class ProjectCalloutService {
    public static Id opportunityId;
    
    @InvocableMethod
    public static void postOpportunityToPMS(List<Id> opportunityIds){
        opportunityId=opportunityIds.get(0);
        Opportunity opp=[Select Id,Name, closeDate,amount,Account.Name FROM Opportunity Where Id =: opportunityId];
        ID jobID = System.enqueueJob(new QueueablePMSCall(opp));
    }    
    
    public class QueueablePMSCall implements system.Queueable,Database.AllowsCallouts
    {
        private String jsonOpp;
        private Opportunity opportunityObject;
        public QueueablePMSCall(Opportunity opp)
        {
            opportunityObject=opp;
            JSONGenerator gen = JSON.createGenerator(true);
            gen.writeStartObject();
            gen.writeStringField('opportunityId', opp.Id);
            gen.writeStringField('opportunityName', opp.Name);
            gen.writeStringField('accountName', opp.account.Name);
            gen.writeDateField('closeDate', opp.closeDate);
            gen.writeNumberField('amount', opp.amount);
            
            gen.writeEndObject();            
            
            jsonOpp= gen.getAsString();
            System.debug('jsonOpp: ' + jsonOpp);
            
        }
        public void execute(QueueableContext context) {
            
            ServiceTokens__c token= ServiceTokens__c.getValues('ProjectServiceToken');
            System.debug(token.Token__c);
            
            // create an HTTPrequest object    
            HttpRequest req = new HttpRequest();
            req.setMethod('POST');
            req.setEndpoint('callout:ProjectService/'+ token.Token__c);
            req.setHeader('Content-Type', 'application/json');
            req.setBody(jsonOpp);    
            
            // create a new HTTP object
            Http http = new Http();
            HTTPResponse res = http.send(req);
            if (res.getStatusCode() != 201) {
                System.debug('Error from ' + req.getEndpoint() + ' : ' +
                             res.getStatusCode() + ' ' + res.getStatus());
                
                Opportunity opportunity1=[Select Id, StageName FROM Opportunity Where Id =: opportunityObject.Id];
                opportunity1.StageName='Resubmit Project';
                update opportunity1;
                
            }
            else {
                Opportunity opportunity2=[Select Id, StageName FROM Opportunity Where Id =: opportunityObject.Id];
                opportunity2.StageName='Submitted Project';
                update opportunity2;
            }      
        }
        
    } 
}
Test Class
@isTest
private class ProjectCalloutServiceTest {
  //Implement mock callout tests here
  public static testMethod void testSuccess(){
      Account acc = new Account(Name='Test Account');
      insert acc;
      Opportunity opp = new Opportunity(Name='Test Opportunity',
                        AccountId=acc.id, CloseDate=System.Today(),
                        Amount=12480.00,
                        Type='New Project',
                        StageName='Qualification');
      insert opp;
      Test.startTest();
      Test.setMock(HttpCalloutMock.class, new ProjectCalloutServiceMock());
      Test.stopTest();
      opp.StageName='Closed Won';
      update opp;
      
  }
  public static testMethod void testFailure(){
      Account acc = new Account(Name='Test Account');
      insert acc;
      Opportunity opp = new Opportunity(Name='Test Opportunity',
                        AccountId=acc.id, CloseDate=System.Today(),
                        Amount=12480.00,
                        Type='New Project',
                        StageNAme='Qualification');
      insert opp;
      Test.startTest();
      Test.setMock(HttpCalloutMock.class, new ProjectCalloutServiceMockFailure());
      Test.stopTest();
      opp.StageName='Closed Won';
      update opp;
  }
}

HTTP Callout Success
global class ProjectCalloutServiceMock implements HttpcalloutMock{
   //Implement http mock callout here
   global HttpResponse respond(Httprequest request){
       HttpResponse response = new Httpresponse();
       String resBody = '[Status=Created, StatusCode=201]';
       response.setHeader('Content-Type','application/json');
       response.setBody(resBody);
       response.setStatusCode(201);
       return response;
   }
}
HTTP Callout Fail
 
//ProjectCalloutServiceMockFailure
global class ProjectCalloutServiceMockFailure implements HttpcalloutMock{
   //Implement http mock callout failure here 
   //Implement http mock callout here
   global HttpResponse respond(Httprequest request){
       HttpResponse response = new Httpresponse();
       String resBody = '[Status=Created, StatusCode=501]';
       response.setBody(resBody);
       response.setStatusCode(501);
       return response;
   }
}


 
Best Answer chosen by MedhanieHabte
Ashish KeshariAshish Keshari
Hi,
I do not see you have added the Custom Setting data creation in your data creation. The custom settings data are not available in test as it can vary from environment to environment and hence manually create it. I also noticed, you have not added a @future(callout=true). See my code below - 
ProjectCalloutService
public class ProjectCalloutService {
    
    //method to be invoked by ProcessBuilder apex
    @InvocableMethod
    public static void postOpportunityToPMS(List<Id> oppoIds){
        Opportunity opportunity = [SELECT Id,Name,Account.Name,CloseDate,Amount FROM Opportunity WHERE Id = :oppoIds[0]];
        String serviceToken = ServiceTokens__c.getValues('ProjectServiceToken').Token__c;
        String jsonInput = '{\n' +
        	' "opportunityId" : "'+opportunity.Id+'",\n'+
        	' "opportunityName" : "'+opportunity.Name+'",\n'+
        	' "accountName" : "'+opportunity.Account.Name+'",\n'+
        	' "closeDate" : "'+String.ValueOf(opportunity.CloseDate).mid(0,10)+'",\n'+   
            ' "amoun" : "'+opportunity.Amount+'"\n}';
		System.enqueueJob(new QueueablePMSCall(serviceToken, jsonInput, opportunity.Id));
    }
    
    // future method to make apex callout
    @Future(callout=true)
    private static void postToPMS(String serviceToken, String jsonInput, Id oppoId) {
            HTTPRequest req = new HTTPRequest();
            req.setEndPoint('callout:ProjectService');
            req.setMethod('POST');
            req.setHeader('token',serviceToken);
            req.setHeader('Content-Type', 'application/json;charset=UTF-8');        
            req.setBody(jsonInput);
            HTTP http = new HTTP();
            HTTPResponse res = http.send(req);
            Opportunity opp = new Opportunity(Id=oppoId);
        	if(res.getStatusCode() != 201){
                opp.StageName = 'Resubmit Project';
                System.debug('Failure: ' + res.getStatusCode() + ' ' + res.getStatus());
            } else {
                opp.StageName = 'Submitted Project';                
                System.debug('Success: ' + res.getStatus());
            }
            update opp;
    }
    
    //queueable class to enque the post request
    class QueueablePMSCall implements System.Queueable, Database.AllowsCallouts {
        private String serviceToken;
        private String jsonInput;
        private String Id;
        public QueueablePMSCall(String serviceToken, String jsonInput, Id oppoId){
            this.serviceToken = serviceToken;
            this.jsonInput = jsonInput;
            this.Id = oppoId;
        }
        public void execute(QueueableContext context) {
            postToPMS(serviceToken, jsonInput, Id);
        }
    }
    
}

ProjectCalloutServiceTest
@isTest
private class ProjectCalloutServiceTest {
    //Implement mock callout tests here

    @testSetup static void testSetupdata(){
		//create the opportunity record
        Opportunity opp1 = new Opportunity();
        opp1.Name = 'ABC Corp1';
        opp1.Type = 'New Project';
        opp1.Amount = 1000;
        opp1.CloseDate = Date.today();
        opp1.StageName = 'Submitted Project';
        insert opp1;
		//create the opportunity record
        Opportunity opp2 = new Opportunity();
        opp2.Name = 'ABC Corp2';
        opp2.Type = 'New Project';
        opp2.Amount = 1000;
        opp2.CloseDate = Date.today();
        opp2.StageName = 'Resubmit Project';
        insert opp2;
        //create the Custom Settings
        ServiceTokens__c servToken = new ServiceTokens__c();
        servToken.Name = 'ProjectServiceToken';
        servToken.Token__c = 'shgglskgblsbglbdsflgbldmfbgldb';
        insert servToken;
    }
    
    @isTest static void testPostCalloutSuccess() {
        Opportunity opp = [Select Id, Name FROM Opportunity WHERE Name = 'ABC Corp1' Limit 1];
        List<Id> oppList = new List<Id>();
        oppList.add(opp.Id);
        System.assertEquals('ABC Corp1', opp.Name);
        System.assertEquals(1,oppList.size());
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new ProjectCalloutServiceMock()); 
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        Test.startTest();
        ProjectCalloutService.postOpportunityToPMS(oppList);
        Test.stopTest();    
        // Verify that the response received contains fake values        
        opp = [select StageName from Opportunity where id =: opp.Id];
        System.assertEquals('Submitted Project',opp.StageName);
    }
    
    @isTest static void testPostCalloutFailure() {
        Opportunity opp = [Select Id, Name FROM Opportunity WHERE Name = 'ABC Corp2' Limit 1];
        List<Id> oppList = new List<Id>();
        oppList.add(opp.Id);
        System.assertEquals('ABC Corp2', opp.Name);
        System.assertEquals(1,oppList.size());
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new ProjectCalloutServiceMockFailure()); 
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        Test.startTest();
        ProjectCalloutService.postOpportunityToPMS(oppList);
        Test.stopTest();        
        // Verify that the response received contains fake values        
        opp = [select StageName from Opportunity where id =: opp.Id];
        System.assertEquals('Resubmit Project',opp.StageName);
    }
    
}

 

All Answers

Jean-Noel CasassusJean-Noel Casassus
You need to add values ServiceTokens__c  in your test class
Ashish KeshariAshish Keshari
Hi,
I do not see you have added the Custom Setting data creation in your data creation. The custom settings data are not available in test as it can vary from environment to environment and hence manually create it. I also noticed, you have not added a @future(callout=true). See my code below - 
ProjectCalloutService
public class ProjectCalloutService {
    
    //method to be invoked by ProcessBuilder apex
    @InvocableMethod
    public static void postOpportunityToPMS(List<Id> oppoIds){
        Opportunity opportunity = [SELECT Id,Name,Account.Name,CloseDate,Amount FROM Opportunity WHERE Id = :oppoIds[0]];
        String serviceToken = ServiceTokens__c.getValues('ProjectServiceToken').Token__c;
        String jsonInput = '{\n' +
        	' "opportunityId" : "'+opportunity.Id+'",\n'+
        	' "opportunityName" : "'+opportunity.Name+'",\n'+
        	' "accountName" : "'+opportunity.Account.Name+'",\n'+
        	' "closeDate" : "'+String.ValueOf(opportunity.CloseDate).mid(0,10)+'",\n'+   
            ' "amoun" : "'+opportunity.Amount+'"\n}';
		System.enqueueJob(new QueueablePMSCall(serviceToken, jsonInput, opportunity.Id));
    }
    
    // future method to make apex callout
    @Future(callout=true)
    private static void postToPMS(String serviceToken, String jsonInput, Id oppoId) {
            HTTPRequest req = new HTTPRequest();
            req.setEndPoint('callout:ProjectService');
            req.setMethod('POST');
            req.setHeader('token',serviceToken);
            req.setHeader('Content-Type', 'application/json;charset=UTF-8');        
            req.setBody(jsonInput);
            HTTP http = new HTTP();
            HTTPResponse res = http.send(req);
            Opportunity opp = new Opportunity(Id=oppoId);
        	if(res.getStatusCode() != 201){
                opp.StageName = 'Resubmit Project';
                System.debug('Failure: ' + res.getStatusCode() + ' ' + res.getStatus());
            } else {
                opp.StageName = 'Submitted Project';                
                System.debug('Success: ' + res.getStatus());
            }
            update opp;
    }
    
    //queueable class to enque the post request
    class QueueablePMSCall implements System.Queueable, Database.AllowsCallouts {
        private String serviceToken;
        private String jsonInput;
        private String Id;
        public QueueablePMSCall(String serviceToken, String jsonInput, Id oppoId){
            this.serviceToken = serviceToken;
            this.jsonInput = jsonInput;
            this.Id = oppoId;
        }
        public void execute(QueueableContext context) {
            postToPMS(serviceToken, jsonInput, Id);
        }
    }
    
}

ProjectCalloutServiceTest
@isTest
private class ProjectCalloutServiceTest {
    //Implement mock callout tests here

    @testSetup static void testSetupdata(){
		//create the opportunity record
        Opportunity opp1 = new Opportunity();
        opp1.Name = 'ABC Corp1';
        opp1.Type = 'New Project';
        opp1.Amount = 1000;
        opp1.CloseDate = Date.today();
        opp1.StageName = 'Submitted Project';
        insert opp1;
		//create the opportunity record
        Opportunity opp2 = new Opportunity();
        opp2.Name = 'ABC Corp2';
        opp2.Type = 'New Project';
        opp2.Amount = 1000;
        opp2.CloseDate = Date.today();
        opp2.StageName = 'Resubmit Project';
        insert opp2;
        //create the Custom Settings
        ServiceTokens__c servToken = new ServiceTokens__c();
        servToken.Name = 'ProjectServiceToken';
        servToken.Token__c = 'shgglskgblsbglbdsflgbldmfbgldb';
        insert servToken;
    }
    
    @isTest static void testPostCalloutSuccess() {
        Opportunity opp = [Select Id, Name FROM Opportunity WHERE Name = 'ABC Corp1' Limit 1];
        List<Id> oppList = new List<Id>();
        oppList.add(opp.Id);
        System.assertEquals('ABC Corp1', opp.Name);
        System.assertEquals(1,oppList.size());
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new ProjectCalloutServiceMock()); 
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        Test.startTest();
        ProjectCalloutService.postOpportunityToPMS(oppList);
        Test.stopTest();    
        // Verify that the response received contains fake values        
        opp = [select StageName from Opportunity where id =: opp.Id];
        System.assertEquals('Submitted Project',opp.StageName);
    }
    
    @isTest static void testPostCalloutFailure() {
        Opportunity opp = [Select Id, Name FROM Opportunity WHERE Name = 'ABC Corp2' Limit 1];
        List<Id> oppList = new List<Id>();
        oppList.add(opp.Id);
        System.assertEquals('ABC Corp2', opp.Name);
        System.assertEquals(1,oppList.size());
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new ProjectCalloutServiceMockFailure()); 
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        Test.startTest();
        ProjectCalloutService.postOpportunityToPMS(oppList);
        Test.stopTest();        
        // Verify that the response received contains fake values        
        opp = [select StageName from Opportunity where id =: opp.Id];
        System.assertEquals('Resubmit Project',opp.StageName);
    }
    
}

 
This was selected as the best answer