4

When you are writing multiple testMethods that ultimately start with the same test data, what is the best design for those initilization methods? By best design, I mean what are the implications for code coverage.

I see two possible designs but I cannot locate any references in documentation that indicate whether one is better or not.

Design 1: In your test class, create a method that initializes all the necessary data and that each testMethod can call. This works fine, but my concern here is that the inclusion of a non-testMethod in the test class will interfere with Salesforce's Code Coverage calculations. And is this how test classes end up appearing in your listed of tested/covered Classes and Triggers in Dev Console?

Design 2: Create a separate non-test class with data initialization methods that are called by your test methods in the test classes. This also works but the addition of extra classes is not ideal for controlling proliferation of Apex classes. The class is considered tested and averaged into Code Coverage but that's not necessarily desirable because it's truly just part of your testing infrastructure.

2

I second Lance's point that methods not marked as testMethod in a test class have no impact to Salesforce's calculation of code coverage. This means you can have as many methods as you want that aren't marked as testMethod.

To be clear, what excludes code from coverage calculations is the @isTest annotation, applied at the class level. testMethod simply tells Salesforce that a particular method should be executed as a test to provide code coverage and functional validation.

I also want to respond to your statement, "[Design 2] also works but the addition of extra classes is not ideal for controlling proliferation of Apex classes." In every org I've developed, I always create a TestOrganization class, whose sole purpose is to create test data for all Apex tests in that org. This class is annotated with @isTest and as a result has no impact on code coverage.

The way I use this class is conceptually the same as what your Design 1. Here's an example:

/*
 * Add a user to a single Chatter group. Make sure the user's group
 * membership appears when querying CollaborationGroupMember.
 */
@isTest
private static void testThatAddMemberCreatesCollaborationGroupMember() {

    // Create test data
    TestOrganization org = new TestOrganization();

    // Set parameters for the test
    User theUser = org.getUserByLastName('Xavier');
    CollaborationGroup theGroup =
        org.getCollaborationGroupByName('Test-Driven Development');

    ...
}
5

One other thing to mention in case you missed it - in Spring 15, there is a new annotation called @testsetup for use in test classes. Data created in methods that use this new annotation is available to all test methods in the class - so the data is created first before any tests are run, and you can then reference it in each method (it is rolled back to the original state for each test though)

And I tested it with data factories and it works fine.

  • Looking forward to this annotation. Also, I'm hoping that limitations will be exceeded for method annotated as @testsetup. – Andrii Muzychuk Jan 13 '15 at 8:15
3

Methods not marked as testMethod but located in a test class will not interfere with Salesforce's Code coverage. Hope this helps.

0

Hope you may find this new test data factory library Apex Test Kit useful: https://github.com/ApexTestKit/ApexTestKit

With it we can create arbitrary levels of many to many relationships. And we focus on making up data participated in the test method, rather than the data factory itself.

@isTest
static void testAccountCreation() {
    // create 10 accounts, each has 2 contacts
    ATKWizard.Bag bag = ATKWizard.I().wantMany('Account')
        .total(10)
        .hasMany('Contact')
            .total(20)
            .fields(new Map<String, Object> {
                'FirstName' => '{!name.firstName(female)}',
                'LastName' => '{!name.lastName}'
            })
        .generate();

    List<Account> accountList = (List<Account>)bag.get('Account');
    System.assertEquals(10, accountList.size());
}

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.