[SalesForce] When is it appropriate to use (SeeAllData=true)

At this point I think we're painfully aware that using SeeAllData=true is one of the 7 Deadly Sins of Salesforce (assuming there's just 7). I know, for example, why we shouldn't use it:

  • Can slow tests down massively if you're accessing a lot of data
  • Querying for a specific record today might be gone tomorrow
  • Could cause tests to pass in sandboxes but fail in production
  • Etc…

I feel at this point I'm regurgitating the same old response to SeeAllData=true:

Using SeeAllData is almost always unnecessary except in the rarest of circumstances.

I realised though I don't actually know when it's useful to use it. So when might it be appropriate to use it? I've never come across a situation yet personally and things like Profile persist in test classes.

The only reason I think where I could be useful is that we have an object called Source__c which stores a bunch of records there the name might be Website, Mobile App, CompanyWe'reAPartnerWith1. It's basically interacted with minimally (this was made before the introduction of Custom Metadata Types), but even then I'd just do something like:

Source__c src = new Source__c(
    Name = 'Website'
);

INSERT src;

I did read that querying data is more efficient than performing DML in this way (hence @testSetup), so maybe I'm doing that "wrong"?

Best Answer

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.