0

How can I build an Apex test class to validate a class method that has a @future HTTPRequest setting? The @future method returns a void, but I can't test a void value with a System.assert[Not]Equals...

The change to the system that triggers the future async call happens on user interaction, so any changes to the system would already be set. The scenario is that the user changes an sObject field (Account Owner) and that change triggers the async http request:

trigger AccountOwnerUpdate on Account (after update) {
    for (Account a : Trigger.new){
        if (a.OwnerId != Trigger.oldMap.get(a.Id).OwnerId) {
            List<Account> aId = [Select OwnerId From Account where Id = :a.Id];
            List<User> oName = [Select Name from User where Id = :aId[0].OwnerId];

            String newOwnerName = EncodingUtil.urlEncode(oName[0].Name, 'UTF-8');
            String accountId = a.Id;

            AccountOwnerUpdateTest.remoteUpdateAccountOwner(accountId, newOwnerName);
        }
    }
}


global class AccountOwnerUpdateTest {
     @future(callout = true)
     public static void remoteUpdateAccountOwner(String accountId, String newOwnerName) {

        HttpRequest req = new HttpRequest();
        String endpoint = '[My url]/'+accountId+'/[param]/'+newOwnerName;

        req.setEndpoint(endpoint);
        req.setMethod('GET');

        Http http = new Http();
        HTTPResponse res = http.send(req);

   }
}

@isTest (seeAllData=true)
public class AccountOwnerUpdateTestClass {
    static testMethod void validateOwnerUpdate() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new MockHttpRequestResponseGenerator());
        AccountOwnerUpdateTest.remoteUpdateAccountOwner('id','owner');
        Test.stopTest();
// System.assertEquals([?])
    }
}
  • You are mixing up several ideas here. Assertions do not provide code coverage, but rather, guarantee the functionality works as expected. Also, you can re-query the data to assert on the outcome. It will be much easier to provide guidance if you edit your post to include what code you are trying to test, and what you've tried so far. – Adrian Larson Sep 29 '16 at 18:36
  • Have you looked at Testing HTTP Callouts by Implementing the HttpCalloutMock Interface? It gives some pretty good guidance that applies to your situation here. – Adrian Larson Sep 29 '16 at 19:02
  • @AdrianLarson - yes, but that test is not looking for a void response from the MockHttpRequest – dbcn Sep 29 '16 at 19:27
1

Your use case is one where a future method is called that does a callout.

How do you assert that this happened?

Immediately before AccountOwnerUpdateTest.remoteUpdateAccountOwner('id','owner'); do: Integer calloutsBefore = Limits.getCallouts();

After Test.stopTest() (as the async executuon won't occur until this statement is reached)

System.assertEquals(calloutsBefore+batchsizebeingtested,Limits.getCallouts());

How do you assert the callout worked?

This is more problematic because you have to mock the results so you really can't test the actual remote Http service did what you expect. hence, to address this would be done via integration testing using live users, or Selenium-type tools.

  • Shouldn't all your Limits calls come between startTest() and stopTest()? Specifically, don't you want to do one between the @future execution and stopTest to verify a callout was made? – Adrian Larson Sep 30 '16 at 0:22
  • @adrianlarson oops - right. edited answer; since future doesn't run until Test.stopTest()) the assert has to happen there. Of course, if multiple callouts (multimock), the assertion is more complex – cropredy Sep 30 '16 at 0:27
  • Hmm...I guess you can't really ever test that a callout was fired made then, I forgot about that. You'd have to assert against the mock then, right? – Adrian Larson Sep 30 '16 at 0:28
  • 1
    @adrianlarson one could, i suppose, pass an object known to the testmethod to the mock callout constructor and have the respond method update the object and then the testmethod can assert that the mock was actually invoked – cropredy Sep 30 '16 at 0:32
  • thanks @cropredy @AdrianLarson - I've added the Limits into the test, but the assertion is still failing unless I remove batchsizebeingtested - with that removed, the test passes, but I still have no code coverage. – dbcn Sep 30 '16 at 12:59

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.