Your issue with both your trigger and your test class are because you've hardcoded a userId into your code. This is a very poor practice. You're much safer to select a profile to use for the user who will have the correct permissions to perform the operation.
Further, the user in your sandbox will have a different Id in production than in your sandbox. Regardless, it's not clear why you'd want to limit your trigger to a single user. If you in fact did need this requirement, for security reasons, you'd want to do one of the following to retrieve the userId during runtime:
- store it in a custom setting
- store it in custom metadata
Your test should also use a "RunAs" user. Here's more on the RunAs user and best practices for using one in a unit test:
private class TestRunAs {
public static testMethod void testRunAs() {
// Setup test data
// This code runs as the system user
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User u = new User(Alias = 'standt', Email='standarduser@testorg.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='standarduser@testorg.com');
// Role = 'some Role'; this would be specific to your org if it uses roles
System.runAs(u) {
// The following code runs as user 'u'
System.debug('Current User: ' + UserInfo.getUserName());
System.debug('Current Profile: ' + UserInfo.getProfileId()); }
}
}
You can nest more than one runAs method. For example:
@isTest
private class TestRunAs2 {
public static testMethod void test2() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User u2 = new User(Alias = 'newUser', Email='newuser@testorg.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='newuser@testorg.com');
Role='Support'; // again, specific to your org.
System.runAs(u2) {
// The following code runs as user u2.
System.debug('Current User: ' + UserInfo.getUserName());
System.debug('Current Profile: ' + UserInfo.getProfileId());
// The following code runs as user u3.
User u3 = [SELECT Id FROM User WHERE UserName='newuser@testorg.com'];
System.runAs(u3) {
System.debug('Current User: ' + UserInfo.getUserName());
System.debug('Current Profile: ' + UserInfo.getProfileId());
}
// Any additional code here would run as user u2.
}
}
}
Best Practices for Using runAs
The following items use the permissions granted by the user specified with runAs running as a specific user:
Dynamic Apex
Methods using with sharing or without sharing
Shared records
The original permissions are reset after runAs completes.
The runAs method ignores user license limits. You can create new users with runAs even if your organization has no additional user licenses.
The Apex Developer Guide explains this error as follows:
SOQL queries can be used to assign a single sObject value when the result list contains only one element. When the L-value of an expression is a single sObject type, Apex automatically assigns the single sObject record in the query result list to the L-value. A runtime exception results if zero sObjects or more than one sObject is found in the list.
What that means is when you assign the result of a SOQL query to a single sObject, and there isn't exactly one sObject returned by the query, you get an exception.
Fortunately, this is easy to fix. Simply assign the SOQL query result to a list instead of a single sObject, and ensure your logic inspects the size of the returned list when deciding on the next step.
List<Zip3_to_LOD__c> results = [
SELECT Id, Name, LOD__c
FROM Zip_3_to_LOD__c
WHERE Name =: contact.Extract_Zipcode__c
];
if (results.size() > 0) {
ziptoLOD2 = results[0];
} else {
ziptoLOD2 = null;
}
Best Answer
Change your query to: