I'm trying to test this simple apex class, but I'm not grasping it.

I have this class:

public with sharing class FinnFeilen {
 public static Account GetUserEmail(){   
    User u = [select id, Name, AccountId from User where id =: userInfo.getUserId()];
    Account acc = [SELECT Id, Name, PersonEmail FROM Account WHERE Id =: u.AccountId LIMIT 1];
    return acc;

But I don't understand how to test this. Mainly because I'm using the userInfo.getUserId(), and that confuses me. But I've tried to create a User and an account in my test class and then using the runAs()-method. But then I'm not able to save because User's AccountId is not writable.

I have this code now, which succeeds, but this can't be a proper test, because it does not use the actual apex-class and returns zero coverage:

private class FinnFeilenTest{
    static testMethod void TestSOQL()
        ID recordTypeId = 'someId'; // replacing for the real test with the proper RecordType Id for personaccounts
        Account account = new Account (
            FirstName = 'Name', 
            LastName = 'Nameson',
            BillingCity = 'Oslo',
            BillingCountry = 'Norway',
            BillingStreet = 'Oslo',
            BillingPostalCode = '1234',
            RecordTypeId = recordTypeId,
            PersonMailingStreet= 'Streetson',
            PersonMailingPostalCode= '2022',
            PersonMailingCity= 'Oslo',
            PersonEmail= 'test@test.no',
            PersonHomePhone= '12345678',
            PersonMobilePhone= '12345678'
        insert account;

        System.assertNotEquals(account, null);

I need guidance on how to proceed on this test. This is my first salesforce-test

  • 4
    Please note that the syntax is system.assertNotEquals(expectedValue, observedValue, meaningfulMessage). You have flipped the first two arguments, which will lead to extremely confusing assertion errors. And while the third parameter is optional, you should never neglect it, as the message you include there gives you the power to explain why the test failed, not just how. – Adrian Larson Jun 27 '18 at 18:14
  • @AdrianLarson That is good to know! – Marius W Jun 28 '18 at 6:15

You need to run the actual code in order to get coverage.

Creating data for tests should be done in a @testSetup method. This has the benefit of being a separate context from the actual test execution. Usually this doesn't matter, but in this case, since you need to either create a user or modify an existing user, you'll need to insert/update these setup records in a separate context from other operations.

private static void Setup() {
    Account acc = new Account();  // Set person account field values as needed 

    insert acc; // may need to wrap in System.RunAs

    Account acc = [Select PersonContactId From Account Where Id = :acc.Id]; // Get new reference to acc 
    // Has personContactId after insert, but need to query to get value 

    User dummyUser = new User(); // Set fields .. 

    dummyUser.ContactId = acc.PersonContactId; // Set contactId to person account 
    // AccountId does not support create/update, but ContactId does ! 
    // https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_user.htm

    insert DummyUser; // make sure we have a value to query 

Now you've got a test that makes data - but you don't meaningfully use that data to do anything. You insert it, which would test any triggers, but to actually cover code outside of triggers, you need to execute the code inside the test (and assert on the result).

Should be as simple as adding this to your test:

User dummyUser = [SELECT Id, AccountId FROM User WHERE Name = 'Dummy User'];

System.RunAs(DummyUser) { // ensure UserInfo gets the right id 
    Account result = FinnFeilen.GetUserEmail(); // get our account 
    // assert fields are equal to user values .. 
    System.assertEquals(dummyUser.AccountId, result.Id); // make sure the accounts are the same 

After doing so, you need to assert that the values returned from your GetUserEmail (Which as an aside, seems poorly named, maybe GetUserAccount instead?) are equal to the values you create in your test.

For other cases, with similiar setups, you can create your data in the test, as long as you have a valid person account user.

User dummyUser = [SELECT Id, AccountId FROM User WHERE Name = 'Dummy User'];

Case c = new Case(AccountId = dummyUser.AccountId); // Set other fields as well 

insert c; // make sure we have a valid value to query before we run our method 

System.RunAs(DummyUser) { // ensure UserInfo gets the right id 
    Case result = FinnFeilen.GetSomeCase(); // get our case, related to an accountId
    System.assertEquals(c.Id, result.Id); // make sure the cases are the same 
| improve this answer | |
  • Okay, but in the setup method: shouldn't I create an account there aswell since I'm trying to fetch an account which is associated with the user? @battery.cord – Marius W Jun 27 '18 at 18:19
  • The trick is you need to set the ContactId on the user, not the AccountId. The user object reference lists the AccountId field as not creatable or updatable, but the ContactId field supports both these operations. Should indirectly set the AccountId as well. Only question I could find for reference found here. – battery.cord Jun 27 '18 at 18:33
  • I cant enable person accounts without the hassle of contacting support, which I didnt realize when I started writing the answer. Let me know if something doesn't line up, so I can edit the answer to be useful for future readers. – battery.cord Jun 27 '18 at 18:34
  • Great. That worked! Thanks, you guys are golden ;) @battery.cord – Marius W Jun 27 '18 at 18:53
  • 1
    Use backticks to set code formatting. Like this. Its this character: `. – battery.cord Jun 27 '18 at 19:00

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.