0

While recently working on a large project where unit test executions would run upwards of 2 hours, we realized we could get a performance gain by avoiding touching the database (e.g. SOQL and DML) during our tests.

So if we wanted to work with Accounts, we might have some code like this:

public class AccountDao
{
    @testVisible private static List<Account> mockResultList = null;  // Does NOT support multiple queries of same SObject in same test!

    public static List<Account> getList() 
    {
        if (mockResultList != null) { System.debug (LoggingLevel.WARN, '!!!!! Unit test uses Account mockResultList: ' + mockResultList); }     

        List<Account> accountList = (Test.isRunningTest() && (mockResultList != null))
                                        ? mockResultList
                                        : [SELECT id, name FROM Account];

        return accountList;
    }
}
}

... where we could feed the expected result into mockResultList before testing the code which would execute AccountDao.getList().

This works fine for our purposes.

But now I am trying to do the same for an ApexClass query.

If I have some Apex class (e.g. a class named "MyClass"), is it possible to somehow add some representation of this to a List<ApexClass>?

2 Answers 2

2

ApexClass is a standard SObject that has fields such as Id, Name, Body, CreatedDate. This executes fine in the developer console:

ApexClass c = new ApexClass(Name = 'MyClass');
System.debug('>>> c=' + c); 

So it looks like you can mock these just as you can any other SObject.

However, if using the real SObjects isn't causing a performance problem then your testing will potentially be more representative if you stick to the real SObjects with their hard to mock underlying behaviours.

2
  • This looks very promising! Will try it. Commented Oct 2, 2014 at 10:05
  • Exactly what I needed! Commented Oct 2, 2014 at 11:02
3

We faced the same problem and went down a different path:

We are mocking the DAO classes (and everything else as well). A typical implementation does look like the following:

public virtual with sharing class AccountDao {

    public virtual List<Account> getAccounts() {
        //SOQL query
    }
}

public virtual with sharing class AccountModifier {

    @TestVisible private AccountDao accountDao = new AccountDao();

    public void doStuff() {
        List<Account> accounts = accountDao.getAccounts();
    }
}

@isTest
private class AccountModifierTest {

    class AccountDaoMock extends AccountDao {

        private List<Account> accounts;

        AccountDaoMock(List<Account> accounts) {
            this.accounts = accounts;
        }

        private Boolean getAccountsHasBeenVisited;
        public override List<Account> getAccounts() {
            getAccountsHasBeenVisited = true;

            return accounts;
        }
    }

    @isTest
    static void testDoStuff() {
        List<Account> accounts = new List<Account>(); //populate list as needed

        AccountDaoMock accountDao = new AccountDaoMock(accounts);

        AccountModifier modifier = new AccountModifier();

        modifier.accountDao = accountDao;

        Test.startTest();

        modifier.doStuff();

        Test.stopTest();

        System.assertEquals(true, accountDao.getAccountsHasBeenVisited);

        // further asserts
    }
}

This approach produces lean, readable code.

The list of ApexClass could be mocked using the JSON conversion described here.

1
  • I really like this approach. I actually was thinking about playing with "virtual" to enable mocking, but I haven't investigated virtual classes much. As I understand SFDC, by default (unlike Java), classes are "final" and "virtual" changes this, but still (unlike abstract) allows for executable code. Are there any drawbacks to making a class virtual? Anything SFDC won't allow you to do with the virtual class that you can with a default/final class? Commented Oct 2, 2014 at 10:08

You must log in to answer this question.

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