1

I am writing a test class for testing an API, which populates the value of an iVAR with the logged in user's time zone. In real time, this API works fine. If the logged in User's time zone is EST, I get the value in EST (after formatting).

However, in the test class, I create a user with a Time zone of PST. Then I use the runAs api to execute code as the new user that I just created. However, the result is as per the logged in user's time zone (EST).

Any pointers would be greatly appreciated.

UPDATE:

Test Code

1. API to create a standard test user, refactored as this is used in multiple places.

public static User getTestUser(String profileName){

    Profile pro = getTestUserProfile(profileName); 

    UserRole role = getUserRole(profileName.equals(System.Label.OperationUserProfile)
                  ? Constants_TVNA.OPS_ROLENAME : Constants_TVNA.SALES_ROLENAME);
    Long randomNumber = Math.mod (Math.mod (System.currentTimeMillis(), 1000000) , 989898989);

    User myUser = new User(alias = 'ABS', 
                 email='[email protected]', 
                   emailencodingkey='UTF-8', 
                   firstname='AB', 
                   lastname='S', 
                   languagelocalekey='en_US', 
                   localesidkey='en_US', 
                   profileId = pro.Id, 
                   userRoleId = role.Id,
                   timezonesidkey='America/Los_Angeles', 
                   username='unittestuser'+randomNumber+'@testorg.com',
                   RestrictRegion_TVNA__c = false, 
                   isActive = true;
    insert   myUser; 
    return myUser;
}

2. Code that is being tested:

public with sharing class ClassBeingTested {
    public String timeZoneShortString;

    public ClassBeingTested() {
        Time_Zone_Abbreviation_TVNA__mdt abbreviation = [Select DeveloperName from Time_Zone_Abbreviation_TVNA__mdt WHERE label = :(UserInfo.getTimeZone().getDisplayName())];
        timeZoneShortString = abbreviation.DeveloperName ;
    }

    public String getTimeZoneShortString() {
        return timeZoneShortString;
    }
}  

3. Testing Code: @isTest public class ClassBeingTested_Test {

static testMethod void orderPDFControllerTest()
{
    System.RunAs(TestDataFactory_TVNA.getTestUser(System.Label.SalesUserProfile)){
         ClassBeingTested cls = new ClassBeingTested();
         System.assertEquals('PST', cls.timeZoneShortString);
        }
}

The logged in user's time zone is EST. When the test case executes, the assert fails. Although when I make the logged in user's time zone as PST, the assert succeeds.

1
  • 2
    Can you post the test code that you are executing to demonstrate this problem?
    – Mark Pond
    Commented Feb 5, 2019 at 22:20

1 Answer 1

2

System's runAs method lacks the documentation on timezone behavior. When you are using this method, the values are automatically changed to the user's timezone when the code is executed.

Outside the method's context the timezone correction only occurs for the running user. This can be demonstrated in this code:

// Considering that 'neutral_user' has 'GMT' as its 'TimeZoneSidKey' field,
// and that the other two users run with 'America/Puerto_Rico' and 
// 'America/Sao_Paulo'.
Datetime christmas2018utc;

System.runAs(neutral_user) {
    // Creates a datetime instance on December 25th, at 12:00 (GMT).
    // Using the 'runAs' method because if we don't, then the date instance will be
    // on the same timezone as the test running user.
    christmas2018utc = Datetime.newInstance(Date.newInstance(2018, 12, 25), Time.newInstance(12, 0, 0, 0));    
}

TimeZone mtz = Timezone.getTimeZone('America/Puerto_Rico'); // UTC-4
TimeZone btz = Timezone.getTimeZone('America/Sao_Paulo'); // UTC-3 (UTC-2 if on DST)
Datetime now = Datetime.now();

Integer m_diff = (mtz.getOffset(now) / 3600000);
Integer b_diff = (btz.getOffset(now) / 3600000);

System.runAs(manaus_user) {
    // In Manaus (Brazil) the timezone is UTC-4, so the hour value will be 8.
    System.debug('For the Manaus user, the time is ' + (12 + m_diff));
    System.assertEquals(12 + m_diff, christmas2018utc.hour());
}

System.runAs(minas_user) {
    // In Belo Horizonte (Brazil) the timezone is UTC-2 (DST), so the hour value will be 10.
    // If it is not on DST, then it will be UTC-3, and the hour value would be 9.
    System.debug('For the Belo Horizonte user, the time is ' + (12 + b_diff));
    System.assertEquals(12 + b_diff, christmas2018utc.hour());
}

If you want to assert the timezone value, do it inside the runAs context.

4
  • Thanks for replying! I understand what you have pointed out. The only gap I think I have is this - When we use runAs, is the logged in user the same as the user I'm executing the code as? Commented Feb 6, 2019 at 14:43
  • No. The transaction context is changed to be that user's. It is similar to using the "Login as" feature. You are using another user to perform operations. Except that during the context of a runAs execution the only thing that is enforced is record sharing. That means that Apex still runs in system mode, ignoring field and user permissions. Commented Feb 6, 2019 at 15:01
  • Oh..that explains it! Thanks. Do you know if there is a way I can simulate the login as for unit testing? I have posted my code above to show what I am trying to achieve. If you can share some thoughts about that, I'd appreciate. Commented Feb 6, 2019 at 16:49
  • Regarding your code, I believe it would be better for you to have a method to receive the custom metadata, and then you can test what the method does. This way you won't be relying on a query. And the "runAs" method is made to test the actions as another user! So it already kind of simulates the "login as" thing. See this question here: salesforce.stackexchange.com/q/118391/18269 Commented Feb 6, 2019 at 19:08

You must log in to answer this question.

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