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
philanthropyphilanthropy 

wrapper class test woes

So I'm writing my first test class and I'm stuck. For my custom controller I adapted a sample wrapper class to my needs. Right now I'm getting 77% coverage but I need to define the selected boolean in my outside class to be true and I can't figure out how to do it. No matter what I try i keep getting an error that cMovie doesnt exist. How do I define cMovie in my test class so I can create an instance and set its boolean to true?

 

I've included my code below:

 

Apex Class:

public class RentalControllerWrapper {
    public List<cMovie> movieList {get;set;}
    public string movieIndex {get;set;}
    //contained class   
    public class cMovie {
         public Movie__c mov {get; set;}
         public Boolean selected {get; set;}
     
         //This is the contructor method. When we create a new cMovie object we pass a Movie that is set to the m property. We also set the selected value to false
         public cMovie(Movie__c m) {
             mov = m;
             selected = false;
         }
    }
     
     //This method uses a simple SOQL query to return a List of Movies
     public List<cMovie> getcMovie() {
         if(movieList == null) {
             movieList = new List<cMovie>();
             for(Movie__c m : [select Id, Name, price__c, description__c, total_inventory__c from Movie__c]) {
                 // As each contact is processed we create a new cMovie object and add it to the movieList
                 movieList.add(new cMovie(m));                 
             }
             //system.debug(movieList[0].mov.id);
         }
         return movieList;
     }
     
     public PageReference RentAllChecked() {
     //We create a new list of Movies if they are selected
     List<Movie__c> selectedMovies = new List<Movie__c>();
     //We will cycle through our list of cContacts and will check to see if the selected property is set to true, if it is we add the Movie to the selectedMovies list
     for(cMovie cMov : getcMovie()) {
         if(cMov.selected == true) {
             selectedMovies.add(cMov.mov);
         }
      }   
      // create new rental record
      Rentals__c newRentalRecord = new Rentals__c();
      insert newRentalRecord;
      
      for(Movie__c mv : selectedMovies) {
         //system.debug(mv);
         mv.total_inventory__c=mv.total_inventory__c-1;
         update mv;         
         // Create new Unit Rental Record and Insert
         Unit_Rental__c newUnitRentalRecord = new Unit_Rental__c();
         newUnitRentalRecord.Movie__c =  mv.ID;
         newUnitRentalRecord.Rental__c = newRentalRecord.ID;   
         insert newUnitRentalRecord;   
      }
      // Redirect to Success page passing rental record ID
      PageReference p = Page.RentalSuccess;
      p.getParameters().put('id', newRentalRecord.ID);
      p.setRedirect(true);
      return p; 
     }
     
     public PageReference Rent() { 
         for(cMovie cMov : getcMovie()) {
            if (cMov.mov.id==movieIndex){
                cMov.selected=true;                
            }
        }
      
        return null;           
     }

 

 

Test Class:

@isTest
private class RentalControllerWrapperTest {

    public static testMethod void RentalControllerWrapper() {
        Movie__c testmov=new Movie__c(Name='Movie1',Release_Date__c=System.now(),Description__c='Description',Price__c=1,Total_Inventory__c=10);
        insert testmov;     
               
        string movieIndex=testmov.ID; 
              
        Test.StartTest();
        RentalControllerWrapper controller=new RentalControllerWrapper();
        
        //controller.List<cMovie> testCMov=new List<cMovie>();
       
        controller.RentAllChecked();
        controller.Rent();                
        
        Test.stopTest(); 
    }
    
}

 VF:

<apex:page controller="RentalControllerWrapper">
 <h1>Rent a Movie</h1><br/><br/>
 <h2>Please Pick movie(s) to rent:</h2>
 <apex:form >
 <apex:pageBlock >
     <apex:pageBlockTable value="{!cMovie}" var="movie_item" id="rentalTable">
         <apex:column headerValue="Movie Title">
             <apex:inputCheckbox id="movieChecked" value="{!movie_item.selected}"/>
             <apex:outputText value="{!movie_item.mov.name}"/>
         </apex:column>
         <apex:column headerValue="Description">
             <apex:outputText value="{!movie_item.mov.Description__c}"/>
         </apex:column>
         <apex:column headerValue="Price">
             <apex:outputText value="${!movie_item.mov.Price__c}"/>
         </apex:column>
         <apex:column headerValue="# In Stock">
             <apex:outputText value="{!movie_item.mov.Total_Inventory__c}"/>
         </apex:column>
         <apex:column headerValue="Rent It">
             <apex:commandButton value="Rent {!movie_item.mov.name}" action="{!rent}" oncomplete="action2();" rerender="rentalTable">             
             <apex:param name="movieIndex" value="{!movie_item.mov.ID}" assignTo="{!movieIndex}" />
             </apex:commandButton>
             <apex:actionFunction name="action2" action="{!rentAllChecked}"/>
         </apex:column>
     </apex:pageBlockTable><br/>
     <apex:commandButton id="rentAllChecked" value="Rent all Checked Movies" action="{!rentAllChecked}" rerender="rentalTable"/>             
    
 </apex:pageBlock>
 </apex:form>
</apex:page>

 

 

 

SteveBowerSteveBower

Hi, a few thoughts...

 

1. You don't have a constructor class in your controller.  There's nothing wrong with putting the query for the movies in the getcmovie() getter, but if you had put it in the constructor instead, you'd have built it when you instantiated the class in your test.   However, since it's not there, you're relying on the getter being called to build your list... but, where in your test code is the page being loaded... :-)

 

You need to look into using:

 

PageReference p = Page.RentalControllerWrapper;

Test.setCurrentPage(p);

 

before you instantiate the controller.  Then your page will load, getters called, etc.

 

 

2. Once you've done that, you should be able to reference and set your movie wrappers with:

 

controller.movieList[7].selected = true;

 

 

Best, Steve.

 

p.s. I should mention that your goal in testing code isn't to achieve code coverage.  It's to check functionality.  So, you should be using System.assert() calls to check that the correct thing happens.  For example, you are creating Unit Rental Record records for the selected movies... your test code should be checking to see if those records got created as expected.  -Steve.

Sam27Sam27

well try something like 

 

 

@isTest
private class RentalControllerWrapperTest {

    public static testMethod void RentalControllerWrapper() {
                   RentalControllerWrapper controller=new RentalControllerWrapper();                                                                                                                      Movie__c testmov = new Movie__c(Name='Movie1',Release_Date__c=System.now(),Description__c='Description',Price__c=1,Total_Inventory__c=10);
        insert testmov;     
               
        string movieIndex=testmov.ID; 
              
        Test.StartTest();
        
        controller.movieList = new List<cMovie>();
        //controller.List<cMovie> testCMov=new List<cMovie>();
       
        controller.RentAllChecked();
        controller.Rent();                
        
        Test.stopTest(); 
    }
     

Practically speaking I didn't find anything wrong in your test method, but I guess then it must be about synchronization, try to manipulate it( look into log too). I m sure you will overcome it. Thanks

philanthropyphilanthropy

Steve, I see your point, just not sure how to do it. I tried adding that code and pointing it to my VF page and its still not working. Am I going to have to move the query into the constructor class? I modeled my wrapper class after a developerforce example (http://wiki.developerforce.com/index.php/Wrapper_Class), if only they had included the test code! Any other ideas, or is that my best option?

 

updated test code:

@isTest
private class RentalControllerWrapperTest {

    public static testMethod void RentalControllerWrapper() {
       
        Movie__c testmov=new Movie__c(Name='Movie1',Release_Date__c=System.now(),Description__c='Description',Price__c=1,Total_Inventory__c=10);
        insert testmov;     
        
        string movieIndex=testmov.ID; 
        
        PageReference p = Page.RentalView2;
        Test.setCurrentPage(p);        
        
        Test.StartTest();
        
        RentalControllerWrapper controller=new RentalControllerWrapper();
        
        //controller.movieList = new List<cMovie>();

        controller.RentAllChecked();
        controller.Rent();                
        
        Test.stopTest(); 
    }
    
}

 

Also, I understand that I should have some assert statements as well to verify things are working correctly but as I said this is my first test case so I'm just trying to figure out how to get through all the code first. Thanks for all the help!

philanthropyphilanthropy

Sam, I tried that code and I'm still getting the now all too familiar error:

Error: Compile Error: Invalid type: cMovie

 

Thanks for the support, I hope to figure it out soon!

SteveBowerSteveBower

Hi, Well, the specific line that is giving you troubles is this one:

 

//controller.List<cMovie> testCMov=new List<cMovie>();

 

And, the reason you can't reference cMovie is that even though it's a public method, you need to qualify it by it's outer class in order to reference it.

 

So, 

 

List<RentalControllerWrapper.cMovie> testCMov = new List<RentalControllerWrapper.cMovie>();

 

should work.   But, again, do you really want to be directly building this list yourself when your code-under-test is supposed to be doing it for you?   Your code has no "inputs", just the movie records in the database already.  So, set those up, then set the current page, then instantiate the controller.

 

Just at that point you ought to be able to:

 

system.assertEquals(1,controller.movieList.size());

 

Then you can call your various controller methods and check the status of other changes in the database.

 

Best, Steve.

 

 

philanthropyphilanthropy

Once again thanks for the help Steve I'm sure once I get this down subsequent tests will HOPEFULLY become easier to write. After reviewing your feedback I added comments to indicate where I feel I'm achieving each step. However, the assert statement you suggested is giving a null pointer exception when executing the test.

 

@isTest
private class RentalControllerWrapperTest {

    public static testMethod void RentalControllerWrapper() {
        // setup existing movie
        Movie__c testmov=new Movie__c(Name='Movie1',Release_Date__c=System.now(),Description__c='Description',Price__c=1,Total_Inventory__c=10);
        insert testmov;     
        
        string movieIndex=testmov.ID; 
        
        
        Test.StartTest();
        // set the current page
        PageReference p = Page.RentalView2;
        Test.setCurrentPage(p);
        //instantiate controller
        RentalControllerWrapper controller=new RentalControllerWrapper();
        
        // assert statement that movieList has been created
        system.assertEquals(1,controller.movieList.size());
        
        //controller.movieList[0].selected=true;  
        controller.RentAllChecked();
        controller.Rent();                
        
        Test.stopTest(); 
    }
    
}

 

 

SteveBowerSteveBower

I misspoke about the getters being fired automatically... you need to fire them yourself since you're not loading them in the constructor. 

 

So, add a    controller.getmovieList()     call after the constructor call.

 

Sorry, Steve.

philanthropyphilanthropy

Thanks again Steve, well I got the following to work:

 

controller.movieList=controller.getcMovie();

I now have 97% coverage but as you stated thats not really the true objective. Its funny though I put a debug statement in there and when I was running it it was populating with data from the real object. How is that possible when its a test? I thought they weren't supposed to do that. Or is it just up to me to code it so that it won't do that?



chubsubchubsub

Hey philanthropy, can you post your final test code?  Thanks! I'm having the same issue, thanks for posting this, it's really helped. 

SayasoniSayasoni

Kindly share your final code.I can't seem to get rid of the Null pointer exception.