0

I'm facing a unique problem while writing a test class for a class which is invoked by a process builder flow. First time, i wrote only test data and relied on the flows which would get triggered and hence the test class passed. But, when I tried moving this into a higher org (which didn't have any active version of the flow) and when the test classes run the one based on flow would fail since process builder flows gets deployed but their status remains deactivated. To fix this i called the specific methods on the class which gets invoked by the flow.

Now a new problem came up (flows deployed and activated now)that when I ran the test classes on higher org where the flows are now active then assertions would fail since technically 2 times the flow gets called. For the test class to pass now the only way is to deactivate the flow and then run the test class.

So, I was thinking if there's any way we can put a check on my test class if a flow is inactive then only call the method of the class explicitly(this class is the one which gets invoked by flow). Is this possible or is there any other workaround?

EDIT: Sharing code for a scenario where on creation of an account with rating as 'Hot' a contact gets created under it automatically. A process builder with entry condition of rating equals 'Hot' had been written which calls a class with invocable method.

Class:

public with sharing class example{

//Using Invocable annotation so that method can be used by Process builder flow
@InvocableMethod(label = 'Insert Contact records' description='Insert Contact records by default on creation of Account record ') 

public static void insertContact(List<Id> accountId){

List<Contact> updatedContactList = new List<Contact>();
List<Account> updatedAccountList = new List<Account>();

for(Account acc : [SELECT Id FROM Account WHERE Id IN:accountId LIMIT : Limits.getLimitQueryRows() - Limits.getQueryRows()] ){

      Contact con = new Contact();
      con.AccountId = acc.Id;
      con.LastName = 'test';
      updatedContactList.add(conc);
      updatedAccountList.add(acc);
}

   Savepoint sp = Database.setSavepoint();
   try{
       if(updatedAccountList.size() > 0){
           Database.upsert(updatedAccountList);
       }
       if(updatedContactList.size() > 0){
           Database.insert(updatedContactList);
       }
   }

   catch(Exception e){
      Database.rollback(sp);
      system.debug('The exception is '+e);
    }
  }
}

Test class block:

Test.startTest();
//Creating account
Account account = new Account();
account.Name = 'test account';
account.Rating = 'Hot';
Database.insert(account);

Account accountInserted = [SELECT Id FROM Account LIMIT 1];

List<Id> accountIdList = new List<Id>();
accountIdList.add(accountInserted.Id);
example.insertContact(accountIdList);
Test.stopTest();

Contact contList=[SELECT Id FROM Contact];
System.assertEquals(1,contList.size()); // this would return 2 if flow is active causing test class to fail; if flow is inactive then this would pass

This is just a hypothetical scenario i'm taking to explain my problem. With process builder it is possible to insert a record without writing any code.

  • This is an x-y problem. Your real question should be how to write your invocable method in a testable way. – Adrian Larson Nov 2 '16 at 14:52
  • @AdrianLarson I've written unit tests for invocable method. The main problem is that as I've already mentioned above is in this case the process builder runs in addition to the explicitly called invocable method which in turn causes my assertions to fail. Any idea as to how I can avoid this? – Sound of Silence Nov 2 '16 at 18:03
  • But your unit tests and invocable method are structured in a way that the flow being active breaks them. It does not have to be so. Kind of hard to say exactly without seeing the method. – Adrian Larson Nov 2 '16 at 18:04
  • @AdrianLarson I've added some code to explain the dilemma. Can you please check? – Sound of Silence Nov 2 '16 at 18:44
  • Where are you getting formula and formulaSpec from? – Adrian Larson Nov 2 '16 at 18:46
2

Never include process builder and whole apex implementation in one change set for Deployment, because process builder behaves in a different way as compared to workflow. Workflow remains active after deployment but we have to enable the process builder manually in target environment. There is some functionality in our test classes / Classes which is dependent on prcoess builder executions which will almost never work if we include process builder in the same change set as our apex implementation.

First include all your processes in one change set and deploy the same. Activate all processes in target env then deploy your apex.

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.