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
jbroquistjbroquist 

File Attachment Unit Test Help

I am creating unit tests for a custom controller I created to handle file uploads and am having issues populating the Attachment body property in my test method. I really just don't know how I'm supposed to simulate a file upload during unit testing.

 

The body property is normally populated from the visualforce apex:inputFile tag, where I bind the inputFile to the attachment body property in my controller.

 

 

<apex:inputFile value="{!file.body}" />

 

 

I know that the Attachment body must be encoded in Base64, but how do I create a variable in my test class that I can use for filesize bounds testing as well? Can anyone provide some direction or even code samples on how I would go about doing this?

 

My test method is as follows:

 

static testMethod void basicControllerTest()
{
System.debug('Unit Test: AttachOppPaperwork Controller');

//Create Opportunity record
Opportunity o = new Opportunity();
o.name = 'Test Opp 1';
o.stageName = 'First Appointment';
o.closeDate = system.today()+60;
insert o;

//Set current page to AttachOppPaperwork
PageReference oPage = new PageReference('/apex/AttachOppPaperwork?id='+o.Id);
Test.setCurrentPage(oPage);

//Instantiate Controller
AttachOppPaperworkController c = new AttachOppPaperworkController();

//Verify variable values
System.assertEquals(o.name, c.oppName); //c.oppName == [Opportunity Name]
System.assertEquals(o.id, c.oppId); //c.oppId == [Opportunity Id]
System.assertNotEquals(null, c.file); //c.file instantiated

//Test File Upload
System.debug('-->AttachOppPaperworkController.upload() called');

//Set file body
//???

//upload the attachment
PageReference uploadTest = c.upload();

System.debug('::AttachOppPaperworkController.attachmentId = ' + c.attachmentId);
System.assertNotEquals(null, c.attachmentId); //attachmentId property should not be null
System.assertEquals(null, uploadTest); //method should return null, refreshing the page
System.assertEquals(true, c.complete); //complete flag should be set to true

//Verify Opportunity field update
Opportunity oTest = [SELECT PaperworkUploadedDate__c FROM Opportunity WHERE Id=:o.Id];

System.debug('::PaperworkUploadedDate__c = ' + oTest.PaperworkUploadedDate__c);
System.assertNotEquals(null, oTest.PaperworkUploadedDate__c); //date field should have a value
}

 

 

bob_buzzardbob_buzzard

Here's how I fill out the body for Unit Testing:

 

 

Blob bodyBlob=Blob.valueOf('Unit Test Attachment Body'); controller.attachment.body=bodyBlob;

 


 

Maurizio BellaMaurizio Bella

Dear bob,

if I push this control I got a failure in my test runner with "attempt to do-reference a null object":

if (sObjAttachment.Body.size() > 2000000 ) {
<something>
}

 this is my code

public PageReference upload() {
    sObjAttachment.OwnerId = UserInfo.getUserId();
    sObjAttachment.ParentId = vUserID;
    sObjAttachment.IsPrivate = false;
    system.debug('sObjAttachment.Body: '+sObjAttachment.Body);
    
    if (sObjAttachment.Body.size() > 2000000 ) {
    	ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO,'You can upload up to 2mb'));
    	return null;
    }
 
    try {
      insert sObjAttachment;
      ApexPages.addMessage(new ApexPages.message(ApexPages.severity.INFO,'Attachment uploaded successfully'));
      sObjAttachment = new Attachment();
    return null;
    } catch (DMLException e) {
      ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Error uploading attachment'));
      return null;
    }
  }


static testMethod void HH_InsertCV_Test1() {
		[...]
		sObjAttachment.ParentId = sObjUser.id;  
	    	sObjAttachment.Name = 'Test Attachment for Parent';  
    		sObjAttachment.Body = b; 
		System.assertEquals(controller.upload(),null);

can you help me please?

thanks for any suggest.

kind regards,

Maurizio 

bob_buzzardbob_buzzard

What does your debug statement on the attachment body output?

Maurizio BellaMaurizio Bella

 

ok fine, the code has always right ;-)

 

this is the problem:

11:09:15.804 (804164000)|USER_DEBUG|[30]|DEBUG|sObjAttachment.Body: null
11:09:15.804 (804268000)|HEAP_ALLOCATE|[32]|Bytes:41
11:09:15.804 (804312000)|METHOD_EXIT|[146]|01pd0000001Ef5v|testcontroller.upload()
11:09:15.804 (804410000)|FATAL_ERROR|System.NullPointerException: Attempt to de-reference a null object

 but now I have one more question:

 

how can I test this condition?

if (sObjAttachment.Body.size() > 2000000 ) {

 maybe I can create an attachment with a size more 2mb ... (i'm not sure)

 

and the next one, how can I test the catch (DMLException e) ?

 

try {
      insert sObjAttachment;
      [...something...]
    } catch (DMLException e) {
      [...something...]
    }

thanks very much for your quickly response.

 

kind regards,

Maurizio 

 

 

 

 

 

bob_buzzardbob_buzzard

I'm not sure if there's any restriction on the size of the strings that are used to create the attachment body - you could try to keep appending the characters.  If not, you may need to refactor the max size out to a method and change it dynamically based on the Test.IsRunningTest return value.

 

Rather than catching the DML exception, I'd use Database.insert which returns a structured value - its much easier to parse in code.

Maurizio BellaMaurizio Bella

what wonderful idea, it's working fine. I prefer the second one, to change the vLimitAttachSize during the test, because I'm not sure that I can create a 2mb of attach, too.

sorry, can you explain what do you mean with:


bob_buzzard wrote:

I'd use Database.insert which returns a structured value - its much easier to parse in code.


Thanks again for you precious support.

bob_buzzardbob_buzzard

Sure - where you have DML operations like insert/update/delete, there are equivalents on the standard Database class.

 

So where you might insert a record using:

 

Account acc=new Account(Name='test');
insert acc;

 you can also use:

 

Account acc=new Account(Name='Test');

SaveResult sr=Database.insert(acc);

You can then interrogate the SaveResult to see what happened in terms of success/fail and reasons.   

 

 

Maurizio BellaMaurizio Bella
I'm very sorry bob but I don't understand how I can catch the attachment insert.

I'll try to explain. I have this pagereference:

public PageReference upload() {
  [something]
    }
    try {
      insert sObjAttachment;
    return null;
    } catch (DMLException e) {
      return null;
    }
  }

and with this class the pagereference test work with success (path try {}). How can I test the catch, please? (path catch{}).


static testMethod void Insert_test() {
[something]
Blob b = Blob.valueOf('Test Data');
controller.getsObjAttachment().Body = b;
controller.getsObjAttachment().ParentId = sObjApplicant.id;
controller.getsObjAttachment().Name = 'Test Attachment for Parent';
System.assertEquals(controller.upload(),null);
[something]
}

 thanks for your time and fix my problem.


Kind regards,
Maurizio

 

bob_buzzardbob_buzzard

Ah, sorry - I thought you were asking how to catch the errors and process them.

 

Unfortunately this is one of the downsides of developing in Apex - its difficult to engineer exceptions as you can't tweak the behaviour further down the line.


However, in this case it should be possible if you create another test and don't specify the name for the attachment - as that is a required field your insert will fail.

Maurizio BellaMaurizio Bella

bob_buzzard wrote:

However, in this case it should be possible if you create another test and don't specify the name for the attachment - as that is a required field your insert will fail.


great, now it's working fine. 
Thanks for your support.
Kind regards,
Maurizio

 

bob_buzzardbob_buzzard

No problem - glad to hear its working.