How can I avoid too many SOQL queries on MASSIVE test classes?
I know you said you wanted to avoid breaking the test classes up, but that's exactly what I suggest. Hear me out.
One of the things you can do (and I suggest you do) is simply bypass those trigger dependencies by inserting the data as it should look later in the process. For example, you'd have a class to test the first part of the process and then a second class (or method, even) to test the latter part. In this second method, you can insert data pre-processed. Since, theoretically, you tested this pre-processesing in the first method, you really won't be cheating by manually entering in the second.
Also, though this won't help with SoQL but with readability, I recommend you leverage the @testSetup pattern to do a pre-inserting of records you will need in both methods. Then you won't have to write a big part of the inserts more than once.
Example of the testSetup pattern:
@isTest
private class TestClass {
@TestSetup
public static void setup() {
//insert some records here
}
@isTest static void testMethod1() {
//do stuff
//If you need to manipulate records from the setup() method query for them here
Test.startTest();
//Do more stuff
Test.stopTest();
//asserts could go here
}
}
I have ran into this same problem before and the @testSetup has solved most of it.
However, if I understand you correctly, testSetup may not allow you to set up all your data as you want.
The problem here is with your "way of thinking" I understand you would like to do end to end testing, BUT, in real practice, no user would do all of that in one transaction (VF page stuff, etc). So attempting to test in in one big test method is not actually testing real life situations.
I would structure the test as such:
- TestSetup method - Sets up all required base data (config, related lookup tables, objects used for reference, etc);
- Create test method to cover each step of the process you are testing as it relates to a single transaction. If the user cannot do it in one transaction then do not have your test do it.
- If you are testing controllers / utility classes etc, do test class individually for each of those testing their functionality as well as appropriate error handling.
Designed properly, you do not have to test end to end in a single method as if the sum of all parts works then the whole part is tested. Make sense?
When it comes to testing processes that are way down in the chain of events, if you have tested up until that point, it is ok to create the records using simple DML inserts of what they would look like up until that point. You do not have to use a VF controller for example to create the record, simply use DML to create the data as it would look if the user had successfully reached that point.
In addition to what Sebastian said you can take it one step further and add do something like this.. This will allow you break out each and every situation and it will give you more control over what tests run, and how..
private static void init(Integer testType)
{
//declare lists, maps, whatever
if(testType == 1)
{
//build testdata
}
if(testType == 2)
{
//build testdata
}
}
private static testMethod void dostuff1()
{
init(1);
Test.startTest();
//run test logic
Test.stopTest();
//asserts
}
private static testMethod void dostuff2()
{
init(2);
Test.startTest();
//run test logic
Test.stopTest();
//asserts
}