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

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. – Brian Kessler Oct 2 '14 at 10:05
  • Exactly what I needed! – Brian Kessler Oct 2 '14 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? – Brian Kessler Oct 2 '14 at 10:08

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.