0

I have a VF Page for a Custom Object that asks a User for a PIN and checks it versus a field on the Contact Object which is it's direct Parent.

This Controller Extension is used for 2 other VF Pages, one on Contact and one on Account.

The VF Page uses a non-rendered apex:outputText to reference the field on the Parent Contact.

<apex:outputText value="{!CustomObject__c.Contact_Owner__r.Security_Pin__c}" rendered="false" />

Because this Controller Extension is used with other VF Pages the field is retrieved dynamically.

When I run my test the Contact_Owner__r.Security_PIN__c field is not populating in the Controller Extension, but when I functionally test the VF Page it populates properly.

private String PINRef {get; set;} // Set in the getField() method
public String PINinput {get; set;} // User entered value

// Controller Extension Constructor
public SecurityController(ApexPages.StandardController controller)
{
    SObject obj = controller.getRecord();

    if(obj.getSObjectType() ==CustomObject__c.sObjectType)
    {
        getField('Contact_Owner__r', 'Security_PIN__c', obj);
    }else if(...)
    }
}

private void getField(String parentRelationship, String fieldAPIName, SObject obj)
{
    Contact c = (Contact)obj.getSObject(parentRelationship);
    if( null != c && c.get(fieldAPIName) != null)
    {
        PINRef = String.valueOf(c.get(fieldAPIName));
        hasPIN = true;
    }else
    {
        hasPIN = false;
    }
}

The user enters a PIN in the VF Page and clicks a button which compares the User entered value with the one on the Contact record.

public void checkPin()
{
    if(PINInput != null)
    {
        Blob inputBlob = Blob.valueOf(PINInput);
        Blob inputHash = Crypto.generateDigest('SHA1', inputBlob);
        String result = EncodingUtil.base64encode(inputHash);
        PINMatches = PINRef.equals(result);
    }
}

My test creates and inserts a base Contact record, afterwards it adds the PIN and Updates the Contact record. Then it creates the record for my Custom Object.

static testMethod void testWithTrustAccount()
{
    Contact cont = new Contact(FirstName = F_NAME, LastName = F_NAME);
    insert cont;

    Contact c = [SELECT Id FROM Contact WHERE FirstName = :F_NAME AND LastName = :F_NAME];

    String PIN = '123456';
    Blob PINBlob = blob.valueOf(PIN);
    Blob PINHash = Crypto.generateDigest('SHA1',PINBlob);
    c.Security_PIN__c = EncodingUtil.base64encode(PINHash);

    update c;

    CustomObject__c custom = new CustomObject__c(Name = 'Test Pin', Contact_Owner__c = c.Id);
    insert custom;

    Test.setCurrentPage(Page.SecurityCheckCustomObject); // This was added (1)
    ApexPages.currentPage().getParameters().put('id', custom.Id); //This was added (2).
    ApexPages.StandardController standardController = new ApexPages.StandardController(trust);

    SecurityController testController = new SecurityController(standardController);

    Test.startTest();

        testController.PINInput = '123456';
        testController.checkPin();

    Test.stopTest();

    System.assertEquals(true, testController.hasPin,
        'No PIN found via the CustomObject__c.Contact_Owner__r.Security_PIN__c relationship');
    System.assertEquals(true, testController.PINMatches,
        'The PIN did not match');
}

I suspect it has something to do with how I'm setting the VF Page in my test method. Originally I did not set it at all, but realizing I'm getting the field through the VF Page I decided to set it (1). That didn't work so I that adding the ID of the custom object might help (2), but that didn't work either.

My VF Page works when I functionally test it, but I can't get my test method to see the Security_PIN__c field.

  • Hey Doug, what (and where) is the error message you're getting? – Sebastian Kessel Dec 29 '15 at 21:10
  • @SebastianKessel I'm getting Attempt to de-reference a null object. At is happening in the checkPin() method PINRef.equals(). I'm getting the error because the if( null != c && c.get(fieldAPIName) != null) line in the getField() method is evaluating to false. – dBeltowski Dec 29 '15 at 21:26
  • I would start by adding a line in the checkPin to ensure that PINRef is not null (which could happen if hasPin == false). But I seem to be missing some of your code. I like that you abridged, but perhaps you abridged too much? Also, how is "getField" called? – Sebastian Kessel Dec 29 '15 at 21:29
  • One more thought, I would also use <apex:inputHidden> instead of a non-rendered <apex:outputText> – Sebastian Kessel Dec 29 '15 at 21:31
  • @SebastianKessel I updated my question to better explain what I'm trying to do. My issue is that PINRef is null because c.get(fieldAPIName) is coming up null. I need c.get(fieldAPIName) to not be null in my Test. You're right about the <apex:inputHidden> tag. – dBeltowski Dec 29 '15 at 21:37
2

Try changing the following lines in your test code:

    CustomObject__c custom = new CustomObject__c(Name = 'Test Pin', Contact_Owner__c = c.Id);
    insert custom;

    //New Line
    custom = [select Id, Name, Contact_Owner__r.Security_Pin__c from CustomObject__c where Id = :c.id LIMIT 1];

    Test.setCurrentPage(Page.SecurityCheckCustomObject); // This was added (1)
    ApexPages.currentPage().getParameters().put('id', custom.Id); //This was added (2).
    //Changed Line
    ApexPages.StandardController standardController = new ApexPages.StandardController(custom);
|improve this answer|||||
  • This answer will allow your controller to test correctly, but to me it seems like a work around, we should not have to query the fields to achieve a successful test,, the page should provide the fields, hence the apex:inputhidden should work, but I possibly doesn't. Surely there is another solution not requiring an explicit query, utilising the fields referred to in the VF page? – NZ Dev Jan 21 '19 at 23:21

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.