3

My apex class extracts all the data of a logged in user for an object. how do I replicate this in my Test class. How do I use System.runAs(User)? The test class is running as me when I say in my code to run as test user. How can I overcome this issue?

public string method1(){
    User u = [Select id, name, email from User where id=: UserInfo.getUserId()];
    Account a = [Select id, name from Account where OwnerId =:u.id ];
    //some more code goes here
}
0

2 Answers 2

4

Ultimately, you need to query the user table for the user you want to "run as" and then execute your method.

So something similar to the following.

Class:

public with sharing DataExportClass
{
    public static List<SObject> getData()
    {
        // do some work to get data here and return
    }        
}

Test:

@isTest
private class TestClass
{
    private static void testMyDataExport()
    {
        // setup some test data

        List<user> userForTesting = [SELECT Id FROM User WHERE Id = 'someIdHere' LIMIT 1];

        system.runAs(userForTesting[0]); // normally you want to verify the list has data first as this could cause null exception
        {
            test.startTest();

            // Complete a SOQL call

            test.stopTest();

            // verify the number of records based on your criteria for this specific user
        }
    }
}
4
  • 1
    Can I not create the test user and use that user as system.runas()? Do I call the method getData() inside the system.runas()?
    – Tara
    Feb 26, 2016 at 0:57
  • You can create the user as part of the test yes, I just queried the database in the example as it was easiest to do. Yes, the method must be called within the system.runas(). Running within system.runas() is basically saying: run the code contained within the braces as the user I pass. Feb 26, 2016 at 0:59
  • It doesn't really matter if it's without sharing since OP just queries OwnerId=UserInfo.getUserId().
    – Adrian Larson
    Feb 26, 2016 at 1:04
  • 1
    True. I wrote the answer before their comment though so I didn't know yet :) I'll update the answer asap. Feb 26, 2016 at 1:08
3

First of all, it does not appear necessary to query the User record based on what you have posted. You can change your Account query to just:

public static List<Account> getAllAccounts()
{
    return [SELECT Name FROM Account WHERE OwnerId = :UserInfo.getUserId()];
}

Secondly, you just need to set up a User in your test and then create Account records they own. It will be easier to test this functionality if you have a method that just returns the query results, then put any further processing logic in a different method.

static testMethod void testGetAllAccounts()
{
    User testUser = new User(/*required fields*/);
    insert testUser;

    final Integer recordCount = Limits.getLimitQueries() + 1;
    List<Account> accounts = new List<Account>();
    for (Integer i = 0; i < recordCount; i++)
    {
        accounts.add(new Account(OwnerId=testUser.Id/*, requiredFields*/));
    }
    insert accounts;

    List<Account> allAccounts;
    system.runAs(testUser)
    {
        Test.startTest();
            allAccounts = MyClass.getAllAccounts();
        Test.stopTest();
    }

    system.assertEquals(recordCount, allAccounts.size(),
        'All accounts pertaining to this user should be found);
}

You can add a separate test identical to the above, but set OwnerId=UserInfo.getUserId(), and assertEquals(0, allAccounts.size()). In other words, the query should not find Account records where the OwnerId is not the running user.

5
  • Ok, thank you!! Will try and let you know. But tried something similar to what you have posted before I posted my question here. Will try one more time. Thanks once again.
    – Tara
    Feb 26, 2016 at 1:07
  • I don't get the use of Limits.getLimitQueries() +1 -- why are you fetching the number of SOQL queries that can be issued to decide how many mock Accounts to create? Personally, I'd mock n Accounts with owner = mocked user and m Accounts where owner = UserInfo.getUserId() and then assert n versus getAllAccounts().size()
    – cropredy
    Feb 26, 2016 at 5:36
  • @crop1645 I always do that to make sure there are no queries in a for loop in the trigger context. I also like to make my unit tests atomic, test one thing insofar as it is reasonable.
    – Adrian Larson
    Feb 26, 2016 at 5:39
  • 1
    Hmm, I never thought of that - probably because I don't put queries in for loops - but I can imagine if working on a code base with no trigger frameworks or bad practices or .... this would be one way to suss out that issue, too bad the Limits exception thrown can't identify the original sinning developer :-)
    – cropredy
    Feb 26, 2016 at 6:13
  • @crop1645 Yes, and they shall then be shamed before being smote. If only. :P
    – Adrian Larson
    Feb 27, 2016 at 23:43

You must log in to answer this question.

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