Le test d'une classe planifiable exécutant l'apex de lot donne des résultats incohérents

Aug 19 2020
@isTest(seeAllData = false)
private class interfacetest {

    public static testMethod void testInterfaceScheduler(){
        Product2 testproduct = new Product2(Name='test product',ProductCode = '112233');
        insert testproduct;
        Test.startTest();
        InterfaceCalloutMock fakeResponse = new InterfaceCalloutMock(200);
        Test.setMock(HttpCalloutMock.class, fakeResponse);
        InterfaceSchedule InterfaceSc = new InterfaceSchedule();
        String sch = '0 0 23 * * ?';
        system.schedule('Test Interface Scheduler', sch, InterfaceSc);
        Test.stopTest();
        List<Product_Image__c> images = [select Id from Product_Image__c where Product__c =:testproduct.Id];
        system.assertEquals(1, images.size());
    }

    public static testMethod void testInterfaceBatch(){
        Product2 testproduct = new Product2(Name='test product',ProductCode = '112233');
        insert testproduct;
        Test.startTest();
        InterfaceCalloutMock fakeResponse = new InterfaceCalloutMock(200);
        Test.setMock(HttpCalloutMock.class, fakeResponse);
        InterfaceBatch Batchtest = new InterfaceBatch();
        database.executebatch(Batchtest,100);
        Test.stopTest();
        List<Product_Image__c> images = [select Id from Product_Image__c where Product__c =:testproduct.Id];
        system.assertEquals(1, images.size());
    }

    public class InterfaceCalloutMock implements HttpCalloutMock {
        Integer responseCode {get;set;}
        InterfaceCalloutMock(Integer responseCode){
            this.responseCode = responseCode;
        }
        public HTTPResponse respond(HTTPRequest req) {
            HttpResponse resp = new HttpResponse();
            resp.setStatusCode(responseCode);
            resp.setBody('[{"id":"31A3FCE7-DDEF-40D1-8365A8CAA8809348"}]');
            return resp;
        }
    }

} 

La classe planifiable exécute simplement l'apex du lot dans la méthode d'exécution.

Pour une raison quelconque, testInterfaceScheduler FAILS assertion, tandis que testInterfaceBatch PASSER l'assertion. Je suis incapable de comprendre pourquoi, toute aide est appréciée.

Merci!

Réponses

1 cropredy Aug 19 2020 at 18:13

La raison en est que testInterfaceSchedulervous essayez d'exécuter deux transactions asynchrones aprèsTest.stoptest()

  • Le programmable
  • Le batchable

Test.stopTest () n'exécute que la première transaction asynchrone avant de passer à l'instruction assert. Votre journal de débogage affichera le batch en cours d'exécution, mais cela se produit réellement (dans le contexte du test) après l'assertion.

Maintenant, un moyen de résoudre ce problème est de faire des tests unitaires appropriés

  • lorsque vous testez un programme; il vous suffit de tester son constructeur et la méthode execute (). Ce qui vous importe vraiment, c'est que execute () a démarré un batch. Et vous pouvez simplement vérifier qu'il existe un AsyncApexJob pour le batch. Vous n'êtes pas obligé de tester que le batch démarre.
  • lorsque vous testez un lot, vous fournissez des objets fictifs start()à rechercher, puis vérifiez execute()et finish()faites ce que vous voulez

Si vous passez des arguments de constructeur au batchable, vous pouvez vérifier que le batchable est appelé avec les arguments appropriés en faisant:

@IsTest static void testBatchable() {
   InterfaceSchedule schedulable = new InterfaceSchedulable(args);
   Test.startTest();
   schedulable.execute(null);  // SchedulableContext can't be constructed
   Test.stoptest();  // batchable will execute now
   // do asserts

}

où le calendrier execute()ressemble à ceci

public void execute(SchedulableContext sc) {
  InterfaceBatch batchable = new InterfaceBatch(this.args);  // from Dependency-injected constructor args  
  Database.executeBatch(batchable);
}    

Autrement dit, votre dépendance injecte dans l'ordonnancable certains arguments que vous souhaitez transmettre au batch. Cela signifie que vous aurez un constructeur no args et un constructeur "with args" pour votre planifiable