function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Walter@AdicioWalter@Adicio 

How do you limit/control the records a test method can test against?

How do you get my test method to only work with records created in my test method?

 

For example im trying to setup records to test with in my test method, and i want to limit my asserts to working with these records created in the test method.

 

I dont want the test method to work with "real" records in the Org, because If my test method uses "real" records and i write asserts to test correctly with sandbox records, my test will fail once i move it from the sandbox to production, because the record counts are not the same between the two Orgs.

 

For example when I do something like this test method below, it seems to be testing "real" records, not stricly test records created in the test method. I expect this to assert to zero, but the actual is 10, because I have 10 "real" records in the Org:

 

public static testMethod void testUserVerticalAssociation() { Profile careersPro = [select Id,Name from Profile where UserLicense.Name='Customer Portal Manager Standard' and Name like '%Careers' limit 1]; system.debug('profile is... '+careersPro.Name); User u01 = [select Id,Name,ProfileId from User where Profile.UserType='PowerCustomerSuccess' and IsActive=true limit 1]; u01.ProfileId=careersPro.Id; update u01; system.debug('user is... '+u01.Name); alertController ac = new alertController(); System.runAs(u01) { ac.getCurrentUserInfo(); ac.assignUserToVerticals(); system.assertEquals(0, ac.ProfileAppropriateAlerts.size() ); } }

 

 

 Also I am having a lot of trouble testing logic that works with users and profiles. For example I am finding that I can not insert a profile in a test method. It says DML is not allowed on profile. This means I have to pre-build "real" profile records and then query for those in my test method. So in this sceanrio my test method MUST work with "real" profile records. Strange, what am I doing wrong?

 

 

Im also having trouble with inserting a User record and assigning that User to an appropriate Profile when inserted via a test method. For example my profile query above is not working to use the ID of that profile and assign it to a user upon new user insert in the test method. I get "invalid user type cross reference". I assume this is because its inserting one user license type and the profile is for another user license type. However when i attempt to assign UserType upon new user insert, i get 'UserType not write-able'. So Im not sure how you get around the 'invalid usertype cross reference'.

 

So I am finding I have to pre-build "real" User and profile records, associate the Profile to the User via user update, and update the user accordingly to test my logic.

 

The other thing I am doing wrong and dont understand is when i attempt to use my test method to update "real" records using test methods, since my test method wants to work with "real" records for testing. But what I see is my test method is working with real records for testing but my test method can not update real records via test methods updates.

 

For example if I have my runas() containing the below, with the rest of the test method code the same as the above test method:

 

System.runAs(u01) { for(Solution sO : [select IsPublished from Solution]) { sO.IsPublished=false; update sO; } ac.getCurrentUserInfo(); ac.assignUserToVerticals(); system.assertEquals(0, ac.ProfileAppropriateAlerts.size() ); }

 

I would expect this to be zero, since I went through and set IsPublished=false on all "real" records.

 

Then since ac.assignUserToVerticals(); only add IsPublished=true to ac.ProfileAppropriateAlerts, the list should have none since i unpublished them all.

 

But what i get is an actual of six, since in this scenario the users profile is associated to "careers" keyword, and i have six "real" records with either Platform__c==null or pName.contains('Careers')==true.

 

I must be doing something really wrong to have such a mix of "needing to query real records to test user/profile logic" and "not wanting to test with real records" to get my counts in assert to test correctly.

 

 

 This is the entire class:

 

 

public class alertController { // start variables public string log { get; set;} {log='';} public string userId { get; set;} {userId='';} public string pName =''; public datetime myDateTime = datetime.now(); // map profiles to verticals public Map<String,String> userProfileToSolutionPlatfromMap = new Map<String,String>(); // alerts for profile mapping public List<Solution> profileAppropriateAlerts = new List<Solution>(); // alerts for time to live public List<Solution> timeAppropriateAlerts = new List<Solution>(); // send alerts to the right server public List<Solution> alwaysShowTheseInAlertsPageList = new List<Solution>(); // list of light box alerts public List<Solution> showTheseInLightBoxList = new List<Solution>(); // make the light box not visible by default public boolean lightBoxPopUp { get; set;} {lightBoxPopUp=false;} // hide the alerts on the dashboard by default public boolean alertRenderController { get; set;} {alertRenderController=false;} // end variables /** The next section is the constructor for the page, its all the scripts we will run **/ public alertController() { userId+=UserInfo.getUserId(); // get info about current user getCurrentUserInfo(); // start assign solutions to users assignUserToVerticals(); // lightbox alerts putAlertsIntoLighBox(); } /************* end constructor */ void getCurrentUserInfo() { for(User u2 :[select Id,Profile.Name from User where Id = :UserInfo.getUserId() limit 1]) { pName = u2.Profile.Name; } } void assignUserToVerticals() { for(Solution s : [select Platform__c,Importance__c,Posted__c,Takedown__c,SolutionName,Portal_Version__c, Log__c,Lightbox_Popup__c,SolutionNote from Solution where RecordType.DeveloperName='Messages_and_Alerts' and IsPublished=true order by Ranking__C Desc nulls last,Importance__c Desc nulls last,Posted__c nulls last]) { // if there is no platform selected, give it to everyone if(s.Platform__c==null && s.Posted__c<myDateTime && s.Takedown__c>myDateTime) {profileAppropriateAlerts.add(s);} // if its the 'all vertical' profile, give them everything except 'testing' else if(pName.contains('All Verticals')==true && s.Posted__c<myDateTime && s.Takedown__c>myDateTime) {profileAppropriateAlerts.add(s);} // no matter what give everything to the system admin else if(s.Platform__c!=null && pName.contains('System Administrator')==true && s.Posted__c<myDateTime && s.Takedown__c>myDateTime) {profileAppropriateAlerts.add(s);} // now match up the solution platform with the user profile else if(s.Platform__c!=null && pName.contains('Careers')==true && s.Platform__c.contains('Careers')==true && s.Posted__c<myDateTime && s.Takedown__c>myDateTime) {profileAppropriateAlerts.add(s);} else if(s.Platform__c!=null && pName.contains('Motors')==true && s.Platform__c.contains('Motors')==true && s.Posted__c<myDateTime && s.Takedown__c>myDateTime) {profileAppropriateAlerts.add(s);} else if(s.Platform__c!=null && pName.contains('Real Estate')==true && s.Platform__c.contains('Real Estate')==true && s.Posted__c<myDateTime && s.Takedown__c>myDateTime) {profileAppropriateAlerts.add(s);} } // end assign solutions to users } void putAlertsIntoLighBox() { // start list for lightbox for(Solution s9 : profileAppropriateAlerts) { // if i dont account for a blank value here i get the attempt to dereference a null value error if(s9.Log__c==null || (s9.Log__c!=null && s9.Log__c.contains(userId)==false)) { showTheseInLightBoxList.add(s9); } } // end list for lightbox } /** this next section has all of the list returns - start **/ // return always show alerts public List<Solution> getalwaysShowTheseInAlertsPageList() {return alwaysShowTheseInAlertsPageList;} // return light box alerts public List<Solution> getShowTheseInLightBoxList() {return showTheseInLightBoxList;} // return profile appropriate alerts public List<Solution> getProfileAppropriateAlerts() {return ProfileAppropriateAlerts;} // return time appropriate alerts public List<Solution> getTimeAppropriateAlerts() {return timeAppropriateAlerts;} /************* end */ /** this next method controls the visibility of the lightbox popup & page redirects - start **/ /** this is a new re-write of newCase() method **/ /** this is the current method in csc_frontdoor on test **/ // start method for page run time actions public PageReference controlLightBoxVisibility() { if(profileAppropriateAlerts.size()==0) { PageReference homePage = new PageReference('/home/home.jsp'); homePage.setRedirect(true); return homePage; } if( // check if there are light box alerts for live showTheseInLightBoxList.size()<>0) { // if the light box alert lists are not empty... // render the HTML for them in the page lightBoxPopUp=true; } return null; } // end method for page run time actions /************* end */ /** this next method turns off the light box - start **/ // start method to disable thickbox messages on live public PageReference doNotShowAlertAgain() { for(Solution s5 :showTheseInLightBoxList) { // add the Id for the current user to the log // new method // stop adding the word "null" to the front of my log if(s5.Log__c==null) { s5.Log__c=+UserInfo.getUserId(); } else { s5.Log__c +=' '+UserInfo.getUserId(); } // old method // s5.Log__c += ' '+UserInfo.getUserId(); // Richette wants to change this to only update one alert by ID, not the whole list // update the list update showTheseInLightBoxList; } return null; } // end method to disable thickbox messages on live /************* end */ // start test method public static testMethod void testUserVerticalAssociation() { // find careers profile, for customer portal Profile careersPro = [select Id,Name from Profile where UserLicense.Name='Customer Portal Manager Standard' and Name like '%Careers' limit 1]; system.debug('profile is... '+careersPro.Name); // find motors profile, for customer portal Profile motorsPro = [select Id,Name from Profile where UserLicense.Name='Customer Portal Manager Standard' and Name like '%Motors' limit 1]; system.debug('profile is... '+motorsPro.Name); // find real estate profile, for customer portal Profile realEstatePro = [select Id,Name from Profile where UserLicense.Name='Customer Portal Manager Standard' and Name like '%Motors' limit 1]; system.debug('profile is... '+realEstatePro.Name); // find customer portal user User u01 = [select Id,Name,ProfileId from User where Profile.UserType='PowerCustomerSuccess' and IsActive=true limit 1]; u01.ProfileId=careersPro.Id; update u01; system.debug('user is... '+u01.Name); // initiate controller alertController ac = new alertController(); System.debug('>>>>>>>>>>>> Start test 1.'); System.debug('test what happens when all live alerts have no verticals selected...'); // run as test user System.runAs(u01) { // setup pName // User u02 = [select Id,Profile.Name from User where Id = :UserInfo.getUserId() limit 1]; // ac.pName=u02.Profile.Name; // system.debug('pName is...'+ac.pName); // clear the current list // ac.ProfileAppropriateAlerts.clear(); // unpublish all solutions for(Solution sO : [select IsPublished from Solution]) { sO.IsPublished=false; update sO; } ac.getCurrentUserInfo(); ac.assignUserToVerticals(); system.assertEquals(0, ac.ProfileAppropriateAlerts.size() ); // change three solutions, published, alive, no platform // for(Solution s2 : [select Id,Platform__c,IsPublished,Posted__c,Takedown__c // from Solution where RecordType.DeveloperName like 'Messages_and_Alerts' limit 3]) // { // s2.Platform__c=''; // s2.IsPublished=true; // s2.Posted__c = datetime.newInstance(2008, 1, 1); // s2.Takedown__c = datetime.newInstance(2010, 1, 1); // update s2; // } // ac.getCurrentUserInfo(); // ac.assignUserToVerticals(); // system.assertEquals(3, ac.ProfileAppropriateAlerts.size() ); // System.debug('>>>>>>>>>>>> End test 1.'); } // end run as } // end test method }

 

Best Answer chosen by Admin (Salesforce Developers) 
wesnoltewesnolte

Hey

 

You can limit the records by simply deleteing them before you start your testing. I have a static method in a utility class that I use to create the database before I create my test data. This ensures consistent  test results no matter what data is in an org. More on this can be found in this article.

 

Cheers,

Wes 

All Answers

Richie DRichie D

Hi Walter,

 

I don't think you can limit the records you test against (probably proved wrong by someone in a bit;) ). The reason being that you should be testing against data that is already in the system. By all means add your own data on top of this but you will get the existing+testdata as a result. You also shouldn't amend your data to make you tests pass (you try setting a parameter) as this (I feel) defeats the point of the test.

 

One thing you could do is calculate how many records you should have instead of assuming that you are only counting your testdata. eg.

 

replace: system.assertEquals(0, ac.ProfileAppropriateAlerts.size() ); with: system.assertEquals([select existing+testdata that match criteria].size, ac.ProfileAppropriateAlerts.size() );

 

 

This will take into account the existing data.

 

As far as your profiles problem goes, you cannot programmatically create or amend profiles with DML. I dont know what to suggest about this so hopefully someone else can pickup on this.

 

Not sure if you are aware of this but all test methods run in their own transaction and everything (data) is returned to the state it was in before so don't worry about updating real data- it won't be updated outside of the testmethod.

 

Regards,

Rich.

 

 

wesnoltewesnolte

Hey

 

You can limit the records by simply deleteing them before you start your testing. I have a static method in a utility class that I use to create the database before I create my test data. This ensures consistent  test results no matter what data is in an org. More on this can be found in this article.

 

Cheers,

Wes 

This was selected as the best answer
wesnoltewesnolte

Oh and BTW the data you delete during the test will 'reappear' after the test is run, so no need to worry about losing any crucial data.

 

Wes 

Richie DRichie D

Wes,

 

Your line "This ensures consistent  test results no matter what data is in an org." to me defeats the point of test methods in certain scenarios. If you are only interested in data you prime to pass your tests then your tests will always pass (unless your code/data is incorrect). Surely the point of testmethods is to check whatever data is in your org. I would have said that your testmethods would be incorrect and need reavaluating if they don't work for existing data. 

 

It is obviously valid to test a subset of data (test primed data) in some cases to check specific functions for example but be careful about doing this to get your tests to pass...

 

Just my thoughts.

Rich. 

wesnoltewesnolte

Hey

 

This is true except that it is the developer's responsibility to create unit tests and data that cover every eventuality not just the expected ones. Creating unit tests in an Org that has data already makes it difficult to see how you testing will behave if your Org has no(or different) data and for this reason I suggest: 

 

1. Clearing all data and performing yours tests to see how they behave in an empty environment

2. Clear all data and create positive testing data to see that your code works when the data is in a good state

3. Clear all data and systematically create negative datasets that test how your code will behave in partial/bad data states.

 

If you really feel like it, you can then run your tests against whatever data is in your Org, and they should still work because you've tested for each eventuality. Of course each person will have their own methodology.

 

Wes

Walter@AdicioWalter@Adicio

Wes and Richie. All good stuff. I have a better understanding.

 

This is very helpful.

 

 

replace:system.assertEquals(0, ac.ProfileAppropriateAlerts.size() );with:system.assertEquals([select existing+testdata that match criteria].size, ac.ProfileAppropriateAlerts.size() );

 Thanks again.

 

 

DcoderDcoder

Hi,

 

Really good post, but could not get answer to the question:

 

If the profile that we want to test, does not exist then how to Insert it in testmethod?

 

Could anyone please suggest on this.

 

thanks.

WesNolte__cWesNolte__c

Unfortunately that wouldn't be possible. You'll need to create or deploy the profile to the Org that you want to run your test against.

 

Wes