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
Will SlotterbackWill Slotterback 

Test Class for Custom Attachment

In one of Jeff Douglas's blog posts he demonstrated how to create a custom Attachment related list for specific objects. http://blog.jeffdouglas.com/2014/05/30/how-to-customize-salesforce-attachments/ 
I've implemented that code to work with our custom Project object by following his examples, but I don't know how to write the test classes for both the VisualForce page and the Apex class so that we can put this custom object into production. I would really appreciate it if someone could provide a test class for this code or at least get me started. 

The code I've written thus far is below:

The Apex Controller:
public with sharing class UploadAttachmentController {
    
    public String selectedType {get;set;}
    public String description {get;set;}
    public MPM4_BASE__Milestone1_Project__c project {get;set;} 
    public Project_Attachment__c attachment {get;set;}
    public String fileName {get;set;}
    public Blob fileBody {get;set;}
    
    public UploadAttachmentController(ApexPages.StandardController controller) { 
        this.project = (MPM4_BASE__Milestone1_Project__c)controller.getRecord();
    }   
    
    // creates a new Project_Attachment__c record
    private Database.SaveResult saveCustomAttachment() {
        Project_Attachment__c obj = new Project_Attachment__c();
        obj.Project__c = project.Id; 
        obj.description__c = description;
        obj.type__c = attachment.Type__c;
        // fill out cust obj fields
        return Database.insert(obj);
    }
    
    // create an actual Attachment record with the Contact_Attachment__c as parent
    private Database.SaveResult saveStandardAttachment(Id parentId) {
        Database.SaveResult result;
        
        Attachment attachment = new Attachment();
        attachment.body = this.fileBody;
        attachment.name = this.fileName;
        attachment.parentId = parentId;
        // insert the attachment
        result = Database.insert(attachment);
        // reset the file for the view state
        fileBody = Blob.valueOf(' ');
        return result;
    }
    
    /**
    * Upload process is:
    *  1. Insert new Contact_Attachment__c record
    *  2. Insert new Attachment with the new Contact_Attachment__c record as parent
    *  3. Update the Contact_Attachment__c record with the ID of the new Attachment
    **/
    public PageReference processUpload() {
        try {
            Database.SaveResult customAttachmentResult = saveCustomAttachment();
        
            if (customAttachmentResult == null || !customAttachmentResult.isSuccess()) {
                ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 
                  'Could not save attachment.'));
                return null;
            }
        
            Database.SaveResult attachmentResult = saveStandardAttachment(customAttachmentResult.getId());
        
            if (attachmentResult == null || !attachmentResult.isSuccess()) {
                ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 
                  'Could not save attachment.'));            
                return null;
            } else {
                // update the custom attachment record with some attachment info
                Project_Attachment__c customAttachment = [select id from Project_Attachment__c where id = :customAttachmentResult.getId()];
                customAttachment.name = this.fileName;
                customAttachment.Attachment__c = attachmentResult.getId();
                update customAttachment;
            }
        
        } catch (Exception e) {
            ApexPages.AddMessages(e);
            return null;
        }
        
        return new PageReference('/'+project.Id);
    }
    
    public PageReference back() {
        PageReference pgRef = new PageReference('/'+ this.project.Id);
        pgRef.setRedirect(true);
        return pgRef; 
    }     
 
}
The VisualForce Page:
<apex:page StandardController="MPM4_BASE__Milestone1_Project__c" tabStyle="MPM4_BASE__Milestone1_Project__c" extensions="UploadAttachmentController">
 
 <apex:sectionHeader title="{!MPM4_BASE__Milestone1_Project__c.Name}" subtitle="Attach File"/>
 
 <apex:form id="form_Upload">
 <apex:pageBlock >
 
 <apex:pageBlockButtons >
   <apex:commandButton action="{!back}" value="Back to Project"/>
   <apex:commandButton action="{!back}" value="Cancel"/>
 </apex:pageBlockButtons>
 <apex:pageMessages />
 
  <apex:pageBlockSection columns="1">
  
    <apex:pageBlockSectionItem >
      <apex:outputLabel value="File" for="file_File"/>
      <apex:inputFile id="file_File" value="{!fileBody}" filename="{!fileName}"/>
    </apex:pageBlockSectionItem>
  
    <apex:pageBlockSectionItem >
      <apex:outputLabel value="Type" for="type"/>
      <apex:inputfield value="{!attachment.Type__c}" id="type" required="true"/> 
    </apex:pageBlockSectionItem> 
    
    <apex:pageBlockSectionItem >
      <apex:outputLabel value="Description" for="description"/> 
      <apex:inputTextarea id="description" value="{!description}" rows="4" cols="50"/>
    </apex:pageBlockSectionItem>
    
    <apex:pageBlockSectionItem >
      <apex:outputLabel value="" for="uploadBtn"/> 
      <apex:commandButton id="uploadBtn" value="Attach File" action="{!processUpload}" />
    </apex:pageBlockSectionItem>    
    
  </apex:pageBlockSection>
 
 </apex:pageBlock> 
 
 </apex:form>
 
</apex:page>

 
Best Answer chosen by Will Slotterback
Daniel BallingerDaniel Ballinger
Looks like you want to test the controller extension. As a good starting point have a read of Testing Custom Controllers and Controller Extensions.

The important part in your Test case(s) is to get the PageReference to your Visualforce page and then pass that to Test.setCurrentPage(pageRef);

You will also need to create an instance of MPM4_BASE__Milestone1_Project__c. Take the Id from the records after insertion and put it in the ApexPages ID.
 
ApexPages.currentPage().getParameters().put('Id', theRecord.Id);
After that your test case can construct an instance of UploadAttachmentController, set the properties with test data, and call processUpload(). That will give you a good deal of coverage. Don't forget to make some meaningful assertions in the test cases to verify that it worked as expected. Some negative test cases for things you expect to fail would be good as well.
 

All Answers

Daniel BallingerDaniel Ballinger
Looks like you want to test the controller extension. As a good starting point have a read of Testing Custom Controllers and Controller Extensions.

The important part in your Test case(s) is to get the PageReference to your Visualforce page and then pass that to Test.setCurrentPage(pageRef);

You will also need to create an instance of MPM4_BASE__Milestone1_Project__c. Take the Id from the records after insertion and put it in the ApexPages ID.
 
ApexPages.currentPage().getParameters().put('Id', theRecord.Id);
After that your test case can construct an instance of UploadAttachmentController, set the properties with test data, and call processUpload(). That will give you a good deal of coverage. Don't forget to make some meaningful assertions in the test cases to verify that it worked as expected. Some negative test cases for things you expect to fail would be good as well.
 
This was selected as the best answer
Will SlotterbackWill Slotterback
Daniel,

Thanks for your help. By following your instructions I was able to get enough code coverage to put the feature into production. If anyone is curious here is the working code for the tests:
 
@isTest
private class UploadAttachmentControllerTest {
    
    static testMethod void testMyController() {
        PageReference pageRef = new PageReference('/apex/UploadAttachment?id=');
        Test.setCurrentPage(pageRef);
        
        // Create new instance of a Project
        MPM4_BASE__Milestone1_Project__c project = new MPM4_BASE__Milestone1_Project__c(Name = 'Test Project');
        insert project;
        
        // Adds the id of the inserted project to the page
        ApexPages.currentPage().getParameters().put('Id', project.Id);
        
        // Create instance of controller
        UploadAttachmentController controller = new UploadAttachmentController(new ApexPages.StandardController(project));
        UploadAttachmentController nullController = new UploadAttachmentController(new ApexPages.StandardController(project));
        
        // Set test fields for controller
        controller.description = 'Test Description';
        controller.fileName = 'TestName.txt';
        controller.fileBody = Blob.valueOf(' ');
        // Set test fields for the null controller
        nullController.description = null;
        nullController.fileName = null;
        nullController.fileBody = null;
            
        controller.processUpload();
        
        
        // Test that processing an upload works as expected and then returns you to the original page
        System.assert(true, new PageReference('/' +project.Id) == controller.processUpload());
        // Test that processing an upload on null fields returns null
        System.assert(true, null == nullController.processUpload());
        // Test that the back button works as expected
        System.assert(true, new PageReference('/' +project.Id) == controller.back());
       
    }
}

 
Raghu Rao 6Raghu Rao 6
I implemented the same set of code for customizing attachments but it's throwing me this error message: common.apex.runtime.impl.DmlExecutionException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Required fields are missing: [Attachment]: [Attachment]"

Code paster below for reference:
public class UploadAttachmentController {
    
    public String selectedType {get;set;}
    public Boolean selectedAwesomeness {get;set;}
    public String description {get;set;}
    public Contact_Attachment__c attachment {get;set;}
    private Contact contact {get;set;} 
    public String fileName {get;set;}
    public Blob fileBody {get;set;}
    
    public UploadAttachmentController(ApexPages.StandardController controller) { 
        this.contact = (Contact)controller.getRecord();
    }   
    
    // creates a new Contact_Attachment__c record
    private Database.SaveResult saveCustomAttachment() {
        Contact_Attachment__c obj = new Contact_Attachment__c();
        system.debug('RK Step 1 - Sub Step 1');
        obj.Contact__c = contact.Id; 
        obj.Description__c = description;
        obj.Type__c = selectedType;
        obj.Awesome__c = selectedAwesomeness;
        obj.Name = this.fileName;
        // fill out cust obj fields
        system.debug('RK Step 1 - Sub step 2');
        return Database.insert(obj);
    }
    
    // create an actual Attachment record with the Contact_Attachment__c as parent
    private Database.SaveResult saveStandardAttachment(Id parentId) {
        Database.SaveResult result;
        
        Attachment attachment = new Attachment();
        attachment.body = this.fileBody;
        attachment.name = this.fileName;
        attachment.parentId = parentId;
        system.debug('Parent Id is :'+parentId);
        system.debug('File Name is :'+this.fileName);
        system.debug('File body is :'+this.fileBody);
        // inser the attahcment
        result = Database.insert(attachment);
        // reset the file for the view state
        fileBody = Blob.valueOf(' ');
        return result;
    }
    
    /**
    * Upload process is:
    *  1. Insert new Contact_Attachment__c record
    *  2. Insert new Attachment with the new Contact_Attachment__c record as parent
    *  3. Update the Contact_Attachment__c record with the ID of the new Attachment
    **/
    public PageReference processUpload() {
        try {
             system.debug('RK Step 1');
            Database.SaveResult customAttachmentResult = saveCustomAttachment();
             system.debug('RK Step 2');
            if (customAttachmentResult == null || !customAttachmentResult.isSuccess()) {
                ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 
                  'Could not save attachment.'));
                return null;
            }
            system.debug('RK Step 3');
            Database.SaveResult attachmentResult = saveStandardAttachment(customAttachmentResult.getId());
             system.debug('RK Step 4');
            if (attachmentResult == null || !attachmentResult.isSuccess()) {
                ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 
                  'Could not save attachment.'));            
                return null;
            } else {
                // update the custom attachment record with some attachment info
                system.debug('RK Step 5');
                Contact_Attachment__c customAttachment = [select id from Contact_Attachment__c where id = :customAttachmentResult.getId()];
                customAttachment.name = this.fileName;
                customAttachment.Attachment__c = attachmentResult.getId();
                update customAttachment;
            }
        
        } catch (Exception e) {
            ApexPages.AddMessages(e);
            return null;
        }
        system.debug('RK Step 6');
        return new PageReference('/'+contact.Id);
    }
    
    public PageReference back() {
        system.debug('RK Step 7');
        return new PageReference('/'+contact.Id);
    }     

}