7

I would like to assert that User B cannot access a record that User A had created from a visualforce page.

The problem is I can't seem to throw the same exception a user would normally see when navigating through the UI.

My controller and test class seem straightforward to me.

Controller

public with sharing class SampleController {
    public SampleController(ApexPages.StandardController stdController) {
        ...
    }   
}

Test Class

@isTest
public class TestClass {

    static testMethod void test_sharing() {
        Account account1;

        system.runAs(getUserA()) {
            account1 = new Account();
            insert account1;
        }

        system.runAs(getUserB()) {
            try {
                SampleController controller 
                    = new SampleController( 
                        new ApexPages.StandardController(account1) ); 

                system.assert(false, 'Did not throw');
            }           
            catch (Exception e) {
                system.assert(true);
            }
        }       
    }   
}
8
  • What happens when you call .view method? Commented Dec 17, 2015 at 8:51
  • Also make your controller class as with sharing Commented Dec 17, 2015 at 8:52
  • How do you separate the data from User A to User B. If it's by profile make sure you have created the user with the correct profile, by roles it's a little bit tricky as even if you insert a role for a user you also have to create the hierarchy in the test class. Commented Dec 17, 2015 at 9:14
  • @MohithShrivastava: When calling a class which doesn't have any with sharing or without sharing from test, it works as with sharing. So that wouldn't be a problem. Commented Dec 17, 2015 at 14:42
  • FYI it should really be SampleExtension, not SampleController. You can only have one controller at a time (but multiple extensions).
    – Adrian Larson
    Commented Dec 17, 2015 at 15:28

2 Answers 2

1

See this post. Sharing is enforced when querying records (via SOQL). It doesn't prevent references to records from being passed around.

The error your user sees has nothing to do with your controller extension. It's thrown by the Visualforce framework itself when it queries based on the ID in the url to determine what account to create the StandardController with. That always respects sharing.

1

It doesn't look like you are accessing the record that User A has created, you are only accessing the SObject variable that you created in your test class, which is available to anything within test_sharing(). Wouldn't you want to try querying the record to see if User B has access to it?

Something like this:

@isTest
public class TestClass {

    static testMethod void test_sharing() {
        Account account1;

        system.runAs(getUserA()) {
            account1 = new Account();
            insert account1;
        }

        system.runAs(getUserB()) {
            try {
                Account queryAccount = [Select Id From Account where Id = account1.Id LIMIT 1];

                SampleController controller 
                    = new SampleController( 
                        new ApexPages.StandardController(queryAccount) ); 

                system.assert(false, 'Did not throw');
            }           
            catch (Exception e) {
                system.assert(true);
            }
        }       
    }   
}
5
  • The query there is done in the test class, so what is relevant is whether that class is with sharing. Commented Jan 7, 2016 at 15:42
  • Apex.StandardController(account1) does not query the inserted record, it just takes the data from the SObject passed in to load the Controller. There is no sharing defined for the SObject (because it is not a record, even after the data contained therein has been inserted and become its own record elsewhere), so the definition of the calling class does not matter. This is why an exception is not thrown. The only way an exception would be thrown on account1 for User B is if the account1 SObject variable were set to the result of a query for the [now] inserted record.
    – JeffyB
    Commented Jan 7, 2016 at 16:57
  • Right, but querying it in the test class is pointless for testing sharing in the VF page, because it just tests sharing in the test class. My point is that the page isn't throwing an exception because of anything in Apex, so you can't really repro it with an Apex unit test. Commented Jan 7, 2016 at 17:02
  • With sharing just tells the class how to address sharing depending on the element in question. With regards to records, "with sharing" would enforce defined sharing rules for the object and user in question who created the record. "with sharing" does not define the accessibility of data created within the class, this is controlled by the public, private, and protected modifiers. He may not be creating the page, but it is possible by creating a new page reference and then setting the "current" page reference with the Account ID he just created. (Code in the next comment...)
    – JeffyB
    Commented Jan 7, 2016 at 17:21
  • Test.setCurrentPageReference(new PageReference('Page.Account')); System.currentPageReference().getParameters().put('id', accountID);
    – JeffyB
    Commented Jan 7, 2016 at 17:21

You must log in to answer this question.

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