0

So here's the situation, I have a lot of things that I want to test, and each of these things requires the same data to be present in the org. I was hoping to be able to use the @testSetup annotation to do something like this to populate the data in each of the test classes:

@isTest
public virtual class Test_Setup{
    @testSetup
    public static void setupTest(){
        // insert various records
    }
}

@isTest
public class Test_Thing1 extends Test_Setup{
    // various tests for thing 1
}

⋮

Unfortunately, attempts at different variations of this design produced the following compile errors:

IsTest classes cannot be virtual
IsTest classes cannot be abstract
Defining type for TestSetup methods must be declared as IsTest

By removing both the @TestSetup and @isTest annotation, and having the insert actions in either the Test_Setup constructor or a static initialization block will at least let the code compile, but it seems that the code there is never run.

What is the preferred method for setting up the same data in multiple test classes? Or would the preferred method be to put all of the test methods into a single class?

1

3 Answers 3

3

Normally, I use to follow this approach, creating Utility class for all records to be created and reused by various test classes.

And from individual testSetup, call those utility methods.

Since, the issue is @testsetup should be used in individual test classes and cannot be reused from other test classes that's why I have taken this approach.

@isTest
public class MyClassA_Test
{
    /*
    * This method prepares the test data of this class.
    */
    @testSetup static void prepareSetupData() 
    {
        TestUtil.createUser(/* pass parameters*/);           
    }

    static testMethod void testMethod1()
    {

    }
}

@isTest
public class MyClassB_Test
{
    /*
    * This method prepares the test data of this class.
    */
    @testSetup static void prepareSetupData() {
        TestUtil.createUser(/* pass parameters*/);    
    }

    static testMethod void testMethod2() {  
    }
}


public class TestUtil
{
    public static void createUser(String firstName, String lastName, String profileId)
    {
        //create user for testing


    }
}
3
  • I was trying to avoid putting that boiler plate at the top of all my test classes, but it's starting to look like there is no better option. Looking at the debug logs, it looks like the program execution during a test run always goes directly into a test method or test setup method, and the test class is never actually constructed. It was promising that it was syntactically valid for a test class to inherit from a non-test class, but without the constructor running for the test class, neither the constructor, nor the static initialization block on the parent class would be called.
    – martin
    Commented Jun 20, 2017 at 5:35
  • Test Utility class shall use @isTest too
    – Kaon Z
    Commented Jun 20, 2017 at 5:51
  • 1
    At least judging from non-test classes, the parent's static initialization block isn't called between the METHOD_ENTRY and METHOD_EXIT of the inheriting class's static intialization block, but it is actually called after in the inheriting class's constructor between the CONSTRUCTOR_ENTRY and CONSTRUCTOR_EXIT.
    – martin
    Commented Jun 20, 2017 at 5:54
1

There's another possibility out there:

Make your test setup a non-test class, and define a static initialization block to insert the records you need in your test classes:

public virtual class Test_Setup {
    static {
        // insert various records
    }
}

Then, have all your test classes extend the Test_Setup class, and include a static variable (or static initialization block) that uses the new keyword to construct the test class, which will cause the constructor for the test class to be called, which will in turn cause the code in the Test_Setup class to be called.

@isTest
public class Test_Thing1 extends Test_Setup {    
    public static Test_Thing1 t1 = new Test_Thing1();

    @isTest
    public static void testMethod(){
    }
}

The need to explicitly construct the class adds a bit of boiler plate, so at least from that perspective, there isn't really any advantage over using the same @testSetup method in each test class if you just want to insert values. Also, the dml will count against you for each test method, which would put this technique at a disadvantage.

There is some value though if you want to save references to the inserted records instead of re-querying for them each time:

public virtual class Test_Setup {
    public static Account a;
    static {
        a = new Account(…); 
        insert a;
    }
}

@isTest
public class Test_Thing1 extends Test_Setup {    
    public static Test_Thing1 t1 = new Test_Thing1();

    @isTest
    public static void testMethod(){
        system.debug(Test_Setup.a);
    }
}
0

Use a Test Utility Class and then call this utility class in each Test Class 's @TestSetup

Check this link for more: https://trailhead.salesforce.com/en/modules/apex_testing/units/apex_testing_data

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .