function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
TROGTROG 

Is there any way to create a test class "subroutine"?

Hi, I repeatedly have to create contacts, accounts, opportunities, and countless other custom objects as dependencies for testing x, y, and z.  Perhaps I'm doing this wrong, but when I'm implementing a new trigger, I'm creating a test class for testing that trigger, and within that test class I have a number of methods which correspond one-to-one with my list of test cases that I'm intending to evaluate.  Within each of those methods I'm repeating all the setup tasks required over and over and over again....unnessessarily (I assume) adding significant (redundant) lines of code for test prep.

Is there any way I can abstract this repeated test prep into a "subroutine"?  My current understanding (and education) tells me that I can't, that each test method needs to be 100% "self contained"...but I feel that this can't possibly be right due to the high level of inefficiency.

Thanks!
Best Answer chosen by TROG
Balaji Chowdary GarapatiBalaji Chowdary Garapati
Hello Tim,

 I can explain with an example consider you need to insert Account information with your desired name and in an other test class you need to insert 5 different test Account and return them.

So now write a class with methods to insert account which can be called from multiple classes:
 
@isTest
public class TestUtilities{
/*This class is to have a common place where test records that belongs to any object is prepared and inserterd */

    public static Account create_Account(String AccountName){
    
        Account testAccount=new Account(name=AccountName);//Assiging only name, in case of any required fields you need to enter them
        insert testAccount;
        
        return testAccount;
    }
    
     public static List<Account> create_Account(Integer NoOfAccounts){
    
        List<Account> testAccountList=new List<Account>();
        
        for(integer i=0;i<NoOfAccounts;i++){
        testAccountList.add(new Account(name='Account '+i));
        }
        
        insert testAccountList;
        
        return testAccountList;
    }
    
    }

Now, you have a test class where you would like to insert an account
 
@isTest
Public class sometestclass{
  public static testMethod void testCreationOfAccount(){
  
 Account accountInserted=TestUtilities.create_Account('Account Testing');
 System.assert(accountInserted.name,'Account Testing');

List<Account>accountList=TestUtilities.create_Account(5);  
System.assert(accountList.size(),5);
}
}

Try it!

Thanks,
balaji

All Answers

Balaji Chowdary GarapatiBalaji Chowdary Garapati
@TROG:

  You can create the test data setup in multiple ways:

1) You can have an utility class which contains multiple methods, ideally one method per object and use method overloading(based on your requirment if necessary) to accept different set of parameters which you might need to set while inserting a  record. Refer to these methods from all of your test classes, where ever you need to insert test data. 
- Make the utility class annotated with @isTest so that it wont count towards the characters of code limit.
- This helps you to modify the test data easily, when ever a new validation rule or validation through trigger is written.(one place to maintain)
2) You can also have your test data setup in CSV file which is stored in static resources and use it from all of your test clases! For more info on that, take a look at below link:

https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_testing_load_data.htm

Hope it helps.,

Thanks,
balaji
TROGTROG
Thanks Balaji (again) - that test data load will definitely be useful!  I know this is likely a basic 101-type question, but I still don't know how to call a utility class from within my test class, where whatever I created in my utility class "persists" and is returned/available to my test class method to use and perform my various logic and asserts.  I know the secret likely exists within the various declarations of public, private, global, etc...but I haven't yet figured that out.  Any additional intel you can provide would be greatly appreciated!

Thanks, Tim
Balaji Chowdary GarapatiBalaji Chowdary Garapati
Hello Tim,

 I can explain with an example consider you need to insert Account information with your desired name and in an other test class you need to insert 5 different test Account and return them.

So now write a class with methods to insert account which can be called from multiple classes:
 
@isTest
public class TestUtilities{
/*This class is to have a common place where test records that belongs to any object is prepared and inserterd */

    public static Account create_Account(String AccountName){
    
        Account testAccount=new Account(name=AccountName);//Assiging only name, in case of any required fields you need to enter them
        insert testAccount;
        
        return testAccount;
    }
    
     public static List<Account> create_Account(Integer NoOfAccounts){
    
        List<Account> testAccountList=new List<Account>();
        
        for(integer i=0;i<NoOfAccounts;i++){
        testAccountList.add(new Account(name='Account '+i));
        }
        
        insert testAccountList;
        
        return testAccountList;
    }
    
    }

Now, you have a test class where you would like to insert an account
 
@isTest
Public class sometestclass{
  public static testMethod void testCreationOfAccount(){
  
 Account accountInserted=TestUtilities.create_Account('Account Testing');
 System.assert(accountInserted.name,'Account Testing');

List<Account>accountList=TestUtilities.create_Account(5);  
System.assert(accountList.size(),5);
}
}

Try it!

Thanks,
balaji
This was selected as the best answer
TROGTROG
That looks like exactly what I was looking for!  I think I was just missing the "return" statement.  Another question for you though.  In your example above, if I wanted to test something else using that account(s) created within testCreationOfAccount() which leverages TestUtilities.create_Account(), how would you suggest that I structure it?  My understanding is that I really don't have control in the sequence the methods execute, so I couldn't create a new method that uses the result of the testCreationOfAccount() method to create an account, right?  Said another way, is there any way to create methods that 'build upon' the results of other methods?  Or, would if each thing I wanted to test required an account, I'd just need to have separate and unique methods for each test case and within each of them call the TestUtilities.create_Account() method?

Also...TestUtilities.create_Account() -  can the two methods create_Account(), one creating an individual record and the other creating multiple records, have the same name?

Thanks so much - this will really help me!
Tyler Mowbrey 1Tyler Mowbrey 1
Hi Tim,

Also, you can create static test data to use across all your test cases in in the event you want to re-use data. It would like similar to:
 
@isTest 
private class testClass {

static {    
        pb = [select Id, isActive from Pricebook2 where isStandard=true];
        if (!pb.isActive) {
             pb.isActive = true;
             update(pb);
        }     
                   
        prod = new Product2(Name='test product', IsActive=true);             
        insert(prod);                            

        pbe = new PricebookEntry(Pricebook2Id=pb.Id, Product2Id=prod.Id, IsActive=true, UnitPrice=10);
        insert(pbe);                   
    
        acc = new Account(name='test acc');         
        insert(acc);                                 
    }

@isTest
private static void testMethod()
{
access all static variables here across all methods.
}
}

Hopefull this helps as well.
TROGTROG
Nice!  I never really knew how to use static - thanks for that!  This has been a most informative discussion thread (for me)!
TROGTROG
Tyler, it's not working for me.  When I try to use "static" variables created/defined within the class, but outside of the method that is trying to use them, it's telling me that the variable doesn't exist.  In the example below, it's throwing an error on row 13 stating that "Variable does not exist: acc.name".  Any ideas?  It looks exactly like the coding syntax that you provided...  Thanks!
@isTest 
private class TEST_static_variables {
    
    static {       
        account acc = new Account(name='test acc');         
        insert acc;                                 
    }
    
    @isTest
    private static void test_method()
    {
        // access all static variables here across all methods.
        string account_name = acc.name;
    }
}

 
Tyler Mowbrey 1Tyler Mowbrey 1
Be sure to declare your variables outside the static area. In my exampl I would have put:
 
private static Account acc;
private static Pricebook2 pb;
private static Product2 prod;
private static PricebookEntry pbe;


So to update your code you would have the following:
 
@isTest 
private class TEST_static_variables {
    private static Account acc;
    static {       
        acc = new Account(name='test acc');         
        insert acc;                                 
    }
    
    @isTest
    private static void test_method()
    {
        // access all static variables here across all methods.
        string account_name = acc.name;
    }
}

 
TROGTROG
It works!  Thanks Tyler!