1

Apex Class for REST Callout

public with sharing class FindAnApprenticeship {
    public class Payload{
        @invocableVariable(label='Find An Apprenticeship URL')
        public String FindAnApprenticeshipURL;

        @invocableVariable(label='Field 1 Value')
        public String field1Value;

        @invocableVariable(label='Field 2 Value')
        public String field2Value;
    }

    @InvocableMethod(label='Post to Find An Apprenticeship')
    public static void postToFindAnApprenticeship(List<Payload> payloads){
        Payload p = payloads[0]; //If Bulk, Only Post First To Avoid Overload.  
        Map<String,String> msg = new Map<String,String>();
        String body = ('{"title":"'+ p.field1Value +'","shortDescription":"'+ p.field2Value +'","longDescription":"'+ p.field3Value +'","desiredSkills":"'+ p.field4Value +'","desiredPersonalQualities":"'+ p.field5Value +'","desiredQualifications":"'+ p.field6Value +'","futureProspects":"'+ p.field7Value +'","thingsToConsider":"'+ p.field8Value +'","trainingToBeProvided":"'+ p.field9Value +'","applicationMethod":"'+ p.field10Value +'","supplementaryQuestion1":"'+ p.field11Value +'","supplementaryQuestion2":"'+ p.field12Value +'","expectedDuration":'+ p.field13Value +',"durationType":"'+ p.field14Value +'","applicationClosingDate":"'+ p.field15Value +'","expectedStartDate":"'+ p.field16Value +'","workingWeek":"'+ p.field17Value +'","hoursPerWeek":'+ p.field18Value +',"wageType":"'+ p.field19Value +'","wageUnit":"'+ p.field20Value +'","fixedWage":'+ p.field21Value +',"locationType":"'+ p.field22Value +'","location":{"addressLine1":"'+ p.field23Value +'","addressLine2":"'+ p.field24Value +'","addressLine3":"'+ p.field25Value +'","addressLine4":"'+ p.field26Value +'","addressLine5":"'+ p.field27Value +'","postcode":"'+ p.field28Value +'","town":"'+ p.field29Value +'","additionalInformation":"'+ p.field30Value +'"},"numberOfPositions":'+ p.field31Value +',"employerEdsUrn":'+ p.field32Value +',"providerSiteEdsUrn":'+ p.field33Value +',"contactName":"'+ p.field34Value +'","contactEmail":"'+ p.field35Value +'","contactNumber":"'+ p.field36Value +'","trainingType":"'+ p.field37Value +'","trainingCode":"'+ p.field38Value +'","isEmployerDisabilityConfident":'+ p.field39Value +',"employerWebsiteUrl":"'+ p.field40Value +'","employerDescription":"'+ p.field41Value +'"}');

        System.enqueueJob(new QueueableFindAnApprenticeship(p.FindAnApprenticeshipUrl, 'POST', body));
    }

    Public class QueueableFindAnApprenticeship implements System.Queueable, Database.AllowsCallouts{
        private final String url;
        private final String method;
        private final String body;

        public QueueableFindAnApprenticeship(String url, String method, String body){
            this.url = url;
            this.method = method;
            this.body = body;
        }

        public void execute(System.QueueableContext ctx){
            HttpRequest req = new HttpRequest();
            req.setEndpoint(url);
            req.setMethod(method);
            req.setBody(body);
            req.setHeader('content-type', 'application/json');
            req.setHeader('subscription-key', '******************');
            Http http = new Http();
            if(!Test.isRunningTest()){
                HttpResponse res = http.send(req);
            }
        }
    }
 }

Apex Class for Mock Callout

@isTest
global class FindAnApprenticeshipCalloutsMock implements HttpCalloutMock {
// Implement this interface method
    global HTTPResponse respond(HTTPRequest request) {
         // Create a fake response
            HttpResponse response = new HttpResponse();
            response.setHeader('Content-Type', 'application/json');
            response.setBody('{"title":"TestTitle","shortDescription":"Short Description","longDescription":"Long Description","desiredSkills":"Test Desired Skills"}');
            response.setStatusCode(200);
            return response; 
    }
}

TestClass

@isTest
public class FindAnApprenticeshipCalloutsTest {
    @isTest public static void testPostCallout() {
    // Set mock callout class
    Test.setMock(HttpCalloutMock.class, new FindAnApprenticeshipCalloutsMock());
    // This causes a fake response to be sent
    // from the class that implements HttpCalloutMock.
    HttpResponse response = FindAnApprenticeship.QueueableFindAnApprenticeship();
    }
}

Error

I'm trying to create a test class for my API callout so that I can move it into the live org but I keep getting the error on the test class which says "Method does not exist or incorrect signature: void QueueableFindAnApprenticeship() from the type FindAnApprenticeship".

It's probably something simple but I'm unable to work it out and relatively new to testing and code in general. I definitely need to improve my knowledge.

Once the initial test class is set up correctly I should hopefully be able to continue with developing my test class with no issues.

Any help or explanations will be much appreciated.

Thank you.


Updated Test Class (Is this more on the lines? I must be missing somthing else because it runs but with no test coverage)

@isTest
public class FindAnApprenticeshipCalloutsTest {
    @isTest public static void testPostCallout() {
    // Set mock callout class
    Test.setMock(HttpCalloutMock.class, new FindAnApprenticeshipCalloutsMock());
    // This causes a fake response to be sent
    // from the class that implements HttpCalloutMock.

    Test.startTest();
        Http http = new Http();
        HttpRequest request = new HttpRequest();
        request.setEndpoint('https://apis.apprenticeships.sfa.bis.gov.uk/manage-vacancies-sandbox/v1/apprenticeships');
        request.setMethod('POST');
        request.setHeader('content-type', 'application/json');
        request.setHeader('ocp-apim-subscription-key', '*************************');
        request.setBody('{"title":"apprentice","shortDescription":"test","longDescription":"test","desiredSkills":"test","desiredPersonalQualities":"test","desiredQualifications":"test","futureProspects":"test","thingsToConsider":"test","trainingToBeProvided":"test","applicationMethod":"Online","supplementaryQuestion1":"test","supplementaryQuestion2":"test","expectedDuration":52,"durationType":"Weeks","applicationClosingDate":"2019-12-20","expectedStartDate":"2020-02-20","workingWeek":"test","hoursPerWeek":40,"wageType":"CustomWageFixed","wageUnit":"Weekly","fixedWage":899,"locationType":"OtherLocation","location":{"addressLine1":"4 Test Street","addressLine2":"United Kingdom","addressLine3":"test","addressLine4":"test","addressLine5":"test","postcode":"TE271NG","town":"Planet Earth","additionalInformation":"test"},"numberOfPositions":2,"employerEdsUrn":123456789,"providerSiteEdsUrn":092876543,"contactName":"Danny","contactEmail":"Danny@skillswork.co.uk","contactNumber":"01229583134","trainingType":"Standard","trainingCode":"1","isEmployerDisabilityConfident":true,"employerWebsiteUrl":"https://www.skillswork.co.uk","employerDescription":"Testing"}');
        HttpResponse response = http.send(request);
        //Parse the JSON response
        System.debug(response.getBody());
     Test.stopTest();

    }
}
3

This guard:

        if(!Test.isRunningTest()){
            HttpResponse res = http.send(req);
        }

and the use of

Test.setMock(HttpCalloutMock.class, new FindAnApprenticeshipCalloutsMock());

are mutually incompatible. Your Mock class will never be called if you gate the HTTP call in your production code; remove the gate if you plan to use a Mock.

This is not how you invoke a Mock:

HttpResponse response = FindAnApprenticeship.QueueableFindAnApprenticeship();

The keyword new is missing, but were it not, you'd get a different error because the constructor for that class does not return an HttpResponse.

Instead, simply invoke the functionality normally that makes the callout within your unit test. Once you've called Test.setMock(), the application of the Mock to your callout is made automatically, and the mock response is returned to your application code at the point the callout is made.

Because you're testing asynchronous code, make sure to use Test.startTest() and Test.stopTest() around any calls you make that enqueue a Queueable job. Otherwise, the Queueable will not run in the context of your unit test.

1
  • I removed the gate from the Apex Class so now I should be able to use the Mock class. I've tried to change the TestClass but I'm not sure if I have miss understood and formatted it completely wrong. I have updated my question with the changes to the test class (Could you confirm if it looks okay?). Thank you for your help and outlining the issue for me. @David Jan 16 '20 at 10:25
2

You seem to be confusing classes with methods.

QueueableFindAnApprenticeship is a class, and you defined it like this:

Public class QueueableFindAnApprenticeship...

you cannot do

HttpResponse response = FindAnApprenticeship.QueueableFindAnApprenticeship();

Instead, you can do

FindAnApprenticeship.QueueableFindAnApprenticeship myClass = new FindAnApprenticeship.QueueableFindAnApprenticeship(url, method, body);

Or you can call this method

FindAnApprenticeship.postToFindAnApprenticeship()

which will enqueue a job of the queueable class you defined.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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