+ Start a Discussion
Holly Havelka 10Holly Havelka 10 

Help with Test Class Error: System.QueryException: List has no rows for assignment to SObject

Hi all,

I have this controller: 
public with sharing class ProfileDetailController {
  
  /*Initialization*/
  
  public ProfileDetailController(ApexPages.StandardController stdController) {
    
    Id currentContactId = UserUtils.getCurrentUserContactId();
    
    Id theProfileId = stdController.getRecord().Id;
    
    theProfile = 
      [select Id, FirstName, LastName, Site_Year__c, Email, Phone, MailingCity, MailingState, Facebook_URL__c, Twitter_URL__c, Privacy_Setting__c 
        from Contact
        where Id = :theProfileId];

    settings = [select Display__c,
                Name 
              from Breakthrough_Application_Settings__c 
              where Active__c = true LIMIT 1];
    isDisplayed = settings.Display__c;
    
    // render 'Public' view if this is rhe current user's profile (Contact) or the Privacy Setting is 'Public'
    isPublic = (theProfile.Id == currentContactId || theProfile.Privacy_Setting__c == 'Public');
    
  }
  
  /*End Initialization*/
  
  /*Properties*/
  
  public Contact theProfile { get; private set; }
  public Boolean isPublic { get; private set; }
  public Breakthrough_Application_Settings__c settings { get; set; }
  public Boolean isDisplayed { get; set; }
  
  /*End Properties*/
  
  /*Action Methods*/
  
  /*End Action Methods*/
  
  /*Helper Methods*/
  
  /*End Helper Methods*/
  
}
This is my test class:
@isTest
private class ProfileDetailControllerTest {
  
  // get full profile regardless of Privacy Setting when viewing user's own profile
  static testMethod void viewOwnProfile() {
    
    Account a = AccountUtils.createBreakthroughOrgAccount('Breakthrough Alumni', true);
    Contact c = ContactUtils.createAlumniContact('My', 'Alumnus', 'myalumnus@org.test', a.Id, false);
    c.SYSTEM_Share_Community_User__c = true;
    insert c;
    User u = UserUtils.createAlumniCommunityUser(c, false, true);
    
    // hack to workaround sharing rule
    //ContactShare cs = new ContactShare(ContactId = c.Id, UserOrGroupId = u.Id, ContactAccessLevel = 'Read');
    //insert cs;
    
    Test.startTest();
    
    System.runAs(u) {
      Test.setCurrentPage(Page.ProfileDetail);      
      Id theProfileId = stdController.getRecord().Id;
      ApexPages.StandardController stdController = new ApexPages.StandardController(c);
      ProfileDetailController ext = new ProfileDetailController(stdController);
      
      System.assertEquals(c.Id,    ext.theProfile.Id);
      System.assertEquals('Private',  ext.theProfile.Privacy_Setting__c);
      System.assertEquals(true,    ext.isPublic);
    }
    
    Test.stopTest();
    
  }
  
  // viewing profile of an alumnus with public Privacy Setting
  static testMethod void viewPublicProfile() {
    
    Account a = AccountUtils.createBreakthroughOrgAccount('Breakthrough Alumni', true);
    Contact c1 = ContactUtils.createAlumniContact('My', 'Alumnus1', 'myalumnus1@org.test', a.Id, false);
    Contact c2 = ContactUtils.createAlumniContact('My', 'Alumnus2', 'myalumnus2@org.test', a.Id, false);
    c1.SYSTEM_Share_Community_User__c = true;
    c2.SYSTEM_Share_Community_User__c = true;
    c2.Privacy_Setting__c = 'Public';
    insert new List<Contact> { c1, c2 };
    User u = UserUtils.createAlumniCommunityUser(c1, false, true);

    Breakthrough_Application_Settings__c setting = new Breakthrough_Application_Settings__c();
        setting.Name = '2017';
        setting.Display__c = true;
        setting.Active__c = true;
        insert setting;
    
    // hack to workaround sharing rule
    //ContactShare cs1 = new ContactShare(ContactId = c1.Id, UserOrGroupId = u.Id, ContactAccessLevel = 'Read');
    //ContactShare cs2 = new ContactShare(ContactId = c2.Id, UserOrGroupId = u.Id, ContactAccessLevel = 'Read');
    //insert new List<ContactShare> { cs1, cs2 };
    
    Test.startTest();
    
    System.runAs(u) {
      Test.setCurrentPage(Page.ProfileDetail);
      ApexPages.StandardController stdController = new ApexPages.StandardController(c2);
      ProfileDetailController ext = new ProfileDetailController(stdController);
      
      System.assertEquals(c2.Id,    ext.theProfile.Id);
      System.assertEquals('Public',  ext.theProfile.Privacy_Setting__c);
      System.assertEquals(true,    ext.isPublic);
      System.assertEquals(true, setting.Display__c);
    }
    
    Test.stopTest();
    
  }
  
  // viewing profile of an alumnus with private Privacy Setting
  static testMethod void viewPrivateProfile() {
    
    Account a = AccountUtils.createBreakthroughOrgAccount('Breakthrough Alumni', true);
    Contact c1 = ContactUtils.createAlumniContact('My', 'Alumnus1', 'myalumnus1@org.test', a.Id, false);
    Contact c2 = ContactUtils.createAlumniContact('My', 'Alumnus2', 'myalumnus2@org.test', a.Id, false);
    c1.SYSTEM_Share_Community_User__c = true;
    c2.SYSTEM_Share_Community_User__c = true;
    c2.Privacy_Setting__c = 'Private';
    insert new List<Contact> { c1, c2 };
    User u = UserUtils.createAlumniCommunityUser(c1, false, true);
    Breakthrough_Application_Settings__c setting = new Breakthrough_Application_Settings__c();
        setting.Name = '2017';
        setting.Display__c = true;
        setting.Active__c = true;
        insert setting;
    
    // hack to workaround sharing rule
    //ContactShare cs1 = new ContactShare(ContactId = c1.Id, UserOrGroupId = u.Id, ContactAccessLevel = 'Read');
    //ContactShare cs2 = new ContactShare(ContactId = c2.Id, UserOrGroupId = u.Id, ContactAccessLevel = 'Read');
    //insert new List<ContactShare> { cs1, cs2 };
    
    Test.startTest();
    
    System.runAs(u) {
      Test.setCurrentPage(Page.ProfileDetail);
      ApexPages.StandardController stdController = new ApexPages.StandardController(c2);
      ProfileDetailController ext = new ProfileDetailController(stdController);
      
      System.assertEquals(c2.Id,    ext.theProfile.Id);
      System.assertEquals('Private',  ext.theProfile.Privacy_Setting__c);
      System.assertEquals(false,    ext.isPublic);
      System.assertEquals(true, setting.Display__c);
    }
    
    Test.stopTest();
    
  }
  
}
I am looking for help on why I am getting this error thrown: System.QueryException: List has no rows for assignment to SObject : Class.ProfileDetailController.: line 19, column 1 Class.ProfileDetailControllerTest.viewOwnProfile: line 36, column 1

Any thoughts?
Best Answer chosen by Holly Havelka 10
Alain CabonAlain Cabon
Ok, it lacks the following class but you could also have a problem (not usable) because you use the sharing by the parent for the contact (the parent here is the account).

In Setup -> Security Controls -> Sharing Settings : Contacts 
public class ContactSharing {
   
   public static void manualShareRead(Id recordId, Id userOrGroupId){
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Read';
        cs.ContactId = recordId;
        cs.UserOrGroupId =  userOrGroupId;
        insert cs ;     
   }   
}

When Contact Sharing is set to "Controlled by parent", Contacts may not be shared independently from Accounts, so Contact Sharing Rules are not applied (even if they are defined).

https://help.salesforce.com/articleView?id=000004005&language=en_US&type=1

So if Contact Sharing is set to "Controlled by parent", you could share the account of the contact in the test class like that :
AccountShare accountShare = new AccountShare();
accountShare.AccountId = a.Id;
accountShare.UserOrGroupId = u.Id;
accountShare.AccountAccessLevel = 'Edit';  // or 'Read'
accountShare.ContactAccessLevel = 'Edit';  // or 'Read'
accountShare.OpportunityAccessLevel = 'Edit';   // or 'Read'
insert accountShare ;
Regards

All Answers

Holly Havelka 10Holly Havelka 10
Also, I removed some unique info at the top of controller and test class, so it's actually line 11, column 1 and line 23, column 1 for where the error is occuring.
Alain CabonAlain Cabon
stdController used before it creation.

Id theProfileId = stdController.getRecord().Id;
ApexPages.StandardController stdController = new ApexPages.StandardController(c);
System.runAs(u) {
      Test.setCurrentPage(Page.ProfileDetail);      
     
      ApexPages.StandardController stdController = new ApexPages.StandardController(c);
      Id theProfileId = stdController.getRecord().Id;
      ProfileDetailController ext = new ProfileDetailController(stdController);
      
      System.assertEquals(c.Id,    ext.theProfile.Id);
      System.assertEquals('Private',  ext.theProfile.Privacy_Setting__c);
      System.assertEquals(true,    ext.isPublic);
}
Regards
Alain
Holly Havelka 10Holly Havelka 10
Alain - I tried out your suggestion, but it's still throwing the same error.
Alain CabonAlain Cabon
I suspected something like this (first thing to check) but that is not this variable which is used above (it lacks some lines of code and that doesn't help)

The problem could be the user (not allowed for the contacts) :   

  c1.SYSTEM_Share_Community_User__c = true;

  c1.Privacy_Setting__c = 'Public';
or
  c1.Privacy_Setting__c = 'Private';

 User = UserUtils.createAlumniCommunityUser(c1false, true);

System.runAs(u) {
or 
System.runAs(u) {

Without the constraint of the user, the sample code could work but that doesn't test the profiles.

Regards
Holly Havelka 10Holly Havelka 10
Alain - still no luck on my end with your suggestions.  I feel like it has to do with the fact the page parameter is not being passed through and that is why the controller is coming up with no rows in the assignment.
Alain CabonAlain Cabon
If the contact exists, that should work. The beginning of the Visualforce page: Page.ProfileDetail could be interesting (<apex:page>)

Contact c = ContactUtils.createAlumniContact('My', 'Alumnus', 'myalumnus@org.test', a.Id, false);
c.SYSTEM_Share_Community_User__c = true;
insert c; // does this contact exist? there is no error, it is practically certain.
User u = UserUtils.createAlumniCommunityUser(c, false, true);

Minimal code: that works.
public with sharing class ProfileDetailController {       
    public ProfileDetailController(ApexPages.StandardController stdController) {        
        Id theProfileId = stdController.getRecord().Id;       
        theProfile = 
            [select Id, FirstName, LastName, Email, Phone, MailingCity, MailingState
             from Contact
             where Id = :theProfileId];
        system.debug('id:' + theprofile.id);      
    }    
    public Contact theProfile { get; private set; }
}
 
@isTest
public class ProfileDetailControlleTEST {
    static testMethod void viewOwnProfile() {        
        Account a = new Account(name='test');
        insert a;
        Contact c = new Contact (firstname='fn',lastname='ln',accountid=a.id);
        insert c;     
        Test.startTest();
        ApexPages.StandardController stdController = new ApexPages.StandardController(c);
        // Id theProfileId = stdController.getRecord().Id;
        ProfileDetailController ext = new ProfileDetailController(stdController);       
        Test.stopTest();        
    }
}

Differences:  System.runAs(u) and  Test.setCurrentPage(Page.ProfileDetail);
Holly Havelka 10Holly Havelka 10
Alain - does it help to know that this line in the controller is refering to the page id?:
Id theProfileId = stdController.getRecord().Id;
Also, I am providing the class for the UserUtils, as I think maybe the contact id for the user is not being associated?:
/*
 * User utility methods
 * 
 * 2014
 */
public class UserUtils {
  
  // Constants
  public static final String Alumni_Community_PROFILE_NAME = 'Portal Per Login User';
  public static final String Alumni_Applicant_PROFILE_NAME = 'BTC - Applicant Alumni';
  public static final String User_Applicant_PROFILE_NAME = 'BTC - Applicant User';
  public static final String Standard_User_PROFILE_NAME = 'Standard User';
  
  private static User currentUser = null;
  
  private static Id alumniCommunityProfileId = null;
  private static Id alumniApplicantProfileId = null;
  private static Id userApplicantProfileId = null;
  private static Id standardUserProfileId = null;
  
  // returns the current user's user record
  public static User getCurrentUser() {
    if (currentUser == null) {
      // add additional fields as needed
      for (User u : [select Id, ContactId, Profile.Name
              from User 
              where Id = :UserInfo.getUserId() limit 1]) {
        currentUser = u;
      }
    }
    return currentUser;
  }
  
  // returns the current user's contact id
  public static Id getCurrentUserContactId() {
    return getCurrentUser().ContactId;
  }
  
  // returns the current user's profile name
  public static String getCurrentUserProfileName() {
    return getCurrentUser().Profile.Name;
  }
  
  // returns the profile id for Alumni Community
  public static Id getAlumniCommunityProfileId() {
    if (alumniCommunityProfileId == null) {
      for (Profile p : [select Id from Profile where Name = :Alumni_Community_PROFILE_NAME limit 1]) {
        alumniCommunityProfileId = p.Id;
      }
    }
    return alumniCommunityProfileId;
  }
  
  // returns the profile id for Alumni Applicant Community
  public static Id getalumniApplicantProfileId() {
    if (alumniApplicantProfileId == null) {
      for (Profile p : [select Id from Profile where Name = :Alumni_Applicant_PROFILE_NAME limit 1]) {
        alumniApplicantProfileId = p.Id;
      }
    }
    return alumniApplicantProfileId;
  }

  // returns the profile id for User Applicant Community
  public static Id getuserApplicantProfileId() {
    if (userApplicantProfileId == null) {
      for (Profile p : [select Id from Profile where Name = :User_Applicant_PROFILE_NAME limit 1]) {
        userApplicantProfileId = p.Id;
      }
    }
    return userApplicantProfileId;
  }

  // returns the profile id for Standard User
  public static Id getStandardUserProfileId() {
    if (standardUserProfileId == null) {
      for (Profile p : [select Id from Profile where Name = :Standard_User_PROFILE_NAME limit 1]) {
        standardUserProfileId = p.Id;
      }
    }
    return standardUserProfileId;
  }
  
  // returns true if the current user is an Alumni Community user
  public static Boolean isAlumniCommunityUser() {
    return (getCurrentUserProfileName() == Alumni_Community_PROFILE_NAME); 
  }
  
  // returns true if the current user is an Alumni Applicant user
  public static Boolean isAlumniApplicantUser() {
    return (getCurrentUserProfileName() == Alumni_Applicant_PROFILE_NAME); 
  }
   
  public static User createUser(Contact contact, Id profileId, Boolean triggerUserEmail, Boolean doInsert) {

    // generate alias 
    String firstInitial = contact.FirstName == null ? '' : contact.FirstName.left(1);
    String lastName = contact.LastName == null ? '' : contact.LastName;
    String alias = (firstInitial + lastName).left(8);
    
    // generate community nickname
    String timestamp = String.valueOf(System.now().getTime());
    String communityNickname = alias + timestamp;
    
    // create the user
    User newUser = new User();
    newUser.ContactId = contact.Id;
        newUser.FirstName = contact.FirstName;
        newUser.LastName = contact.LastName;
        newUser.Username =  contact.Email;
        newUser.Email = contact.Email;
        newUser.ProfileId = profileId;
        newUser.LanguageLocaleKey = 'en_US';
        newUser.LocaleSidKey = 'en_US';
        newUser.TimeZoneSidKey = 'America/Los_Angeles';
        newUser.EmailEncodingKey = 'ISO-8859-1';
        newUser.Alias = alias;
        newUser.CommunityNickname = communityNickname;
        newUser.isActive = true;           
    
        // set the DML options to send the new user email
    Database.DMLOptions dmo = new Database.DMLOptions();
      dmo.EmailHeader.triggerUserEmail = triggerUserEmail;
      newUser.setOptions(dmo);  
    
    // insert the user
    if (doInsert) {
      insert newUser;
    }
    
    return newUser;
    
  }
  
  public static User createUser(String userFirstName, String userLastName, String email, Id profileId, Boolean triggerUserEmail, Boolean doInsert) {

    // generate alias 
    String firstInitial = userFirstName == null ? '' : userFirstName.left(1);
    String lastName = userLastName == null ? '' : userLastName;
    String alias = (firstInitial + lastName).left(8);

    // generate community nickname
    String timestamp = String.valueOf(System.now().getTime());
    String communityNickname = alias + timestamp;

    // create the user
    User newUser = new User();
        newUser.FirstName = userFirstName;
        newUser.LastName = userLastName;
        newUser.Username =  email;
        newUser.Email = email;
        newUser.ProfileId = profileId;
        newUser.LanguageLocaleKey = 'en_US';
        newUser.LocaleSidKey = 'en_US';
        newUser.TimeZoneSidKey = 'America/Los_Angeles';
        newUser.EmailEncodingKey = 'ISO-8859-1';
        newUser.Alias = alias;
        newUser.CommunityNickname = communityNickname;
        newUser.isActive = true;           

        // set the DML options to send the new user email
    Database.DMLOptions dmo = new Database.DMLOptions();
      dmo.EmailHeader.triggerUserEmail = triggerUserEmail;
      newUser.setOptions(dmo);  

    // insert the user
    if (doInsert) {
      insert newUser;
    }

    return newUser;
  }
  
  public static User createAlumniCommunityUser(Contact contact, Boolean triggerUserEmail, Boolean doInsert) {
    return createUser(contact, UserUtils.getAlumniCommunityProfileId(), triggerUserEmail, doInsert);
  }
  
  public static User createAlumniApplicantUser(Contact contact, Boolean triggerUserEmail, Boolean doInsert) {
    return createUser(contact, UserUtils.getalumniApplicantProfileId(), triggerUserEmail, doInsert);
  }
  
  public static User createStandardUser(String userFirstName, String userLastName, String email, Boolean triggerUserEmail, Boolean doInsert) {
    return createUser(userFirstName, userLastName, email, UserUtils.getStandardUserProfileId(), triggerUserEmail, doInsert);
  }  
}


 
Holly Havelka 10Holly Havelka 10
Alain - thanks again for all of your help.  There was an issue with the fact that I had a sharing rule in effect, and that is why when we removed the System.runAs (u) was allowing the code to execute without the error.  

Not sure if it's best practice, but I put in a ContactShare rule to allow for this test class to run without error.
Alain CabonAlain Cabon
Ok, that was the user as we suspected.

Could you try this in your test class:

System.assertEquals(ContactSharing.manualShareRead(c.Id, u.Id), true);

Regards
Holly Havelka 10Holly Havelka 10
Alain - that throws anther error: Compile Error: Variable does not exist: ContactSharing at line 46 column 25
Alain CabonAlain Cabon
Ok, it lacks the following class but you could also have a problem (not usable) because you use the sharing by the parent for the contact (the parent here is the account).

In Setup -> Security Controls -> Sharing Settings : Contacts 
public class ContactSharing {
   
   public static void manualShareRead(Id recordId, Id userOrGroupId){
        ContactShare cs = new ContactShare();
        cs.ContactAccessLevel = 'Read';
        cs.ContactId = recordId;
        cs.UserOrGroupId =  userOrGroupId;
        insert cs ;     
   }   
}

When Contact Sharing is set to "Controlled by parent", Contacts may not be shared independently from Accounts, so Contact Sharing Rules are not applied (even if they are defined).

https://help.salesforce.com/articleView?id=000004005&language=en_US&type=1

So if Contact Sharing is set to "Controlled by parent", you could share the account of the contact in the test class like that :
AccountShare accountShare = new AccountShare();
accountShare.AccountId = a.Id;
accountShare.UserOrGroupId = u.Id;
accountShare.AccountAccessLevel = 'Edit';  // or 'Read'
accountShare.ContactAccessLevel = 'Edit';  // or 'Read'
accountShare.OpportunityAccessLevel = 'Edit';   // or 'Read'
insert accountShare ;
Regards
This was selected as the best answer