When is it appropriate to use (SeeAllData=true)

One good reason you may still need to use SeeAllData is for any functionality you have built around Report records. Your tests do not have default access to them, but they cannot be created.

static testMethod void testReports()
{
    system.assertNotEquals(0, [SELECT count() FROM Report]); // fails
}

Another instance where you may need it is Field History Tracking. If you have logic that depends on History records, I believe you cannot get them without SeeAllData.

static testMethod void testCaseHistory()
{
    Case record = (Case)SObjectFactory.create(Case.sObjectType);
    record.Status = 'Some new status';
    update record;
    system.assertNotEquals(0, [SELECT count() FROM CaseHistory]); //fails
}

Even if your code depends on these objects, you can still write it in such a way as to minimize your dependency on their presence in the database. For instance, you may write one method that just performs the query, then another that accepts the query results as a parameter. In this way, you can test most of your logic without needing to actually put data into the database.


In most cases, you can work around the SeeAllData=true limitation by using the Force.com Enterprise Apex Selector pattern and ApexMocks.

here's an example for Dashboard

Your MyClass.doSomething() method uses code such as this:

....
Dashboard[] dashboards = DashBoardsSelector.newInstance()
   .selectByDeveloperName(new Set<String> {'Foo'});

The selector follows the Enterprise pattern and looks like this (excerpted):

public virtual class DashboardsSelector implements IDashboardsSelector{


    public List<Schema.SObjectField> getSObjectFieldList(){
        return new List<Schema.SObjectField> {
                Dashboard.Description,
                Dashboard.DeveloperName,
                ...
        };
    }

    /*  Factory to provide caller with a new Selector. Enables selectors to be mocked */ 
    public static IDashboardsSelector newInstance()    {
        return (IDashboardsSelector)Application.Selector.newInstance(Dashboard.SObjectType);
    }

    /* getSObjectType : Used to construct queries. Required. */
    public Schema.SObjectType getSObjectType() {return Dashboard.SObjectType;}

    /* selectById   : default selector, returns all matching SObjects for fields defined by getSObjectFieldList */
    public virtual List<Dashboard> selectById(Set<Id> ids) {
        return ids.isEmpty() ? new List<Dashboard> () : (Dashboard[]) selectSObjectsById(ids);
    }

    /* selectByDeveloperName  : fetches dashboard for a devname set */
    public virtual List<Dashboard> selectByDeveloperName(Set<String> devNames) {
        if (devNames.isEmpty()) return new List<Dashboard> ();
        fflib_QueryFactory dbQF = newQueryFactory()
                .setCondition('DeveloperName IN :devNames');
        return Database.query(dbQF.toSOQL());
    }
}

The interface for factory and mocking is:

public interface IDashboardsSelector {
  List<Dashboard> selectByDeveloperName(Set<String> devNames);
}

and your Application class has an entry for the selector (not shown here)

Now, your testmethods don't need to use SeeAllData=true, they merely need to mock the selector and the selector's method's return:

fflib_ApexMocks mocks = new fflib_ApexMocks();

//  Given mockDashboards (using Json serialize/deserialize technique - here with Sobject Fabricator github lib)
Dashboard[] mockDashboards = new List<Dashboard> ();
mockDashboards.add((Dashboard) new sfab_FabricatedSObject(Dashboard.class)
                .setField(Dashboard.Id,fflib_IdGenerator.generate(Dashboard.SObjectType))
                .setField(Dashboard.DeveloperName,'FooDash')
                .toSObject());

//  Given a mockSelector
DashboardsSelector mockDashboardsSelector = (DashboardsSelector) mocks.mock(DashboardsSelector.class);
mocks.startStubbing();
mocks.when(mockDashboardsSelector.SObjectType()).thenReturn(Dashboard.SObjectType);
for (Integer i = 0; i < mockDashboards.size(); i++) {
    mocks.when(mockDashboardsSelector
     .selectByDeveloperName(new Set<String> {mockDashboards[i].DeveloperName}))
        .thenReturn(new List<Dashboard>{mockDashBoards[i]});
}
mocks.stopStubbing();
Application.Selector.setMock(mockDashboardsSelector);

// when codeUnderTest method invoked
new MyClass.doSomething(...);

// then verify whatever results you care about

Now this pattern is super useful and allows you to create mock results from SOQl queries against SObjects you can't otherwise insert in testmethods. The ApexMocks library gives you flexibility with selector, domain, service, and unit of work layers and can avoid creating DML actual sobjects in most of your unit tests.

But what about testing the actual selector class itself? How do you know that the method selectByDeveloperName actually does the right thing?

Here, seeAllData=true is required but you have localized it to just the selector class itself and the rest of your unit tests need never depend on org data

private class DashboardsSelectorTest {
    @IsTest(SeeAllData=true)
    static void testSelectors() {

        Dashboard[] orgDashboards = [SELECT ID, DeveloperName From Dashboard Limit 1];
        if (orgDashboards.isEmpty()) {return;}  // can't test, no org dashboards

        Dashboard[] dbs = DashboardsSelector.newInstance()
                .selectByDeveloperName(new Set<String> {orgDashboards[0].DeveloperName});
        System.assertEquals(1,dbs.size(),'should find the real org Dashboard');

    }
}

Tags:

Apex

Unit Test