5

I'm very new to the Dev side of Salesforce, but need to write a unit test for a piece of code that grabs the IDs of any attachment on a Job Applicant (custom object) record.

Is there any really simple way to do this? From what I've read it seems like I need to push dummy data into my own code, which I really wouldn't know how to go about - I simply got an example piece of code and played around with it until it worked - wasn't able to get a dummy unit test.

Here's the code, any help would be much appreciated!

trigger caseAttachment1771 on Attachment (after delete, after insert, after undelete) {
  Map<Id, string> Job_Applicant = new Map<Id, string>();
  for (Attachment attachment : (Trigger.new == null ? Trigger.old : Trigger.new)) {

    if (((string)attachment.ParentId).startswith('a0D')) {
      Job_Applicant.put(attachment.ParentId, '');
    }
  }

  if (Job_Applicant.keySet().size() > 0) {
    for (Attachment a : [SELECT Id, ParentId FROM Attachment WHERE ParentId IN :Job_Applicant.keySet() ORDER BY CreatedDate DESC]) {

      if (Job_Applicant.get(a.ParentId) != '')
        Job_Applicant.put(a.ParentId, Job_Applicant.get(a.ParentId) + '|');
      Job_Applicant.put(a.ParentId, Job_Applicant.get(a.ParentId) +  a.Id);
    }

    List<AVTRRT__Job_Applicant__c> JAList = new List<AVTRRT__Job_Applicant__c>();

    for (Id Job_ApplicantId : Job_Applicant.keySet()) {
      JAList.add(new AVTRRT__Job_Applicant__c(id=Job_ApplicantId, Attach_Ids__c=Job_Applicant.get(Job_ApplicantId)));
    }
    update JAList;
  }
}
  • 1
    Don't use startsWith('a0D'), that isn't portable code. Instead, use attachment.parentId.getSObjectType() == Job_Applicant__c.SObjectType. – sfdcfox Sep 26 '13 at 14:07
7

Correction to Trigger

To make the trigger more robust, don't directly check the key prefix of the ID unless you do so dynamically (e.g. String jobPrefix = AVTRRT__Job_Applicant__c.SObjectType.getDescribe().getKeyPrefix()). An easier way that saves a describe is to check SObjectType values. Code illustration follows.

trigger caseAttachment1771 on Attachment (after insert, after delete, after undelete) {
    Map<Id, String[]> jobs = new Map<Id, String[]>();
    AVTRRT__Job_Applicant__c[] apps = new AVTRRT__Job_Applicant__c[0];

    for(Attachment record: Trigger.new!=null?Trigger.new:Trigger.old) {
        if(record.ParentId.getSObjectType() == AVTRRT__Job_Applicant__c.SObjectType) {
            jobs.put(record.ParentId, new String[0]);
        }
    }
    for(Attachment record: [SELECT Id, ParentId FROM Attachment WHERE ParentId IN :jobs.keySet()]) {
        jobs.get(record.ParentId).add(record.Id);
    }
    for(Id recordId: jobs.keySet()) {
        apps.add(new AVTRRT__Job_Applicant__c(Id=recordId, Attach_Ids__c=String.join(jobs.get(recordId),'|')));
    }
    update apps;
}

Sample Test Method

While it's always best to learn, some people learn by example, so I've included an example here. This code will fully test your trigger and make sure that the logic is working as designed.

// Test method example
@isTest static void test() {
    // Create some parents
    AVTRRT__Job_Applicant__c jobRecord = new AVTRRT__Job_Applicant__c(Name='Test');
    insert jobRecord;
    Account accRecord = new Account(Name='Test');
    insert accRecord;

    // Create some attachments
    Attachment[] attRecords = new Attachment[] {
        new Attachment(ParentId=jobRecord.Id, Name='Test', Body=Blob.valueOf('Test'), ContentType='text/plain'),
        new Attachment(ParentId=accRecord.Id, Name='Test', Body=Blob.valueOf('Test'), ContentType='text/plain')
    };

    // Test insert trigger logic
    insert attRecords;

    // Make sure that Attach_Ids__c has value
    jobRecord = [SELECT Id, Name, Attach_Ids__c FROM AVTRRT__Job_Applicant__c WHERE Id = :jobRecord.Id];
    System.assertEquals(attRecord[0].Id, (Id)jobRecord.Attach_Ids__c);

    // Test delete trigger logic
    delete attRecords[0];

    // Make sure that Attach_Ids__c does not have value
    jobRecord = [SELECT Id, Name, Attach_Ids__c FROM AVTRRT__Job_Applicant__c WHERE Id = :jobRecord.Id];
    System.assertEquals(true, String.isBlank(jobRecord.Attach_Ids__c));

    // Test undelete trigger logic
    undelete attRecords[0];

    // Make sure that Attach_Ids__c has value
    jobRecord = [SELECT Id, Name, Attach_Ids__c FROM AVTRRT__Job_Applicant__c WHERE Id = :jobRecord.Id];
    System.assertEquals(attRecord[0].Id, (Id)jobRecord.Attach_Ids__c);  
}

Note that some logic may still be incorrect. This is meant to be illustrative only, and it's likely that you'll need to change the logic so that required fields are populated, etc.

  • Thanks SFDC Fox! This helps a lot - the only issue is that my Job Applicant Name is an auto-number field, so I get an error when trying to create a 'Test' record - thoughts? – McD Sep 30 '13 at 14:07
  • Simply leave it blank, in that case. Salesforce.com will automatically generate a new number for you. – sfdcfox Sep 30 '13 at 16:06
4

Essentially, there are 3 things every unit test needs. You need to:

  • Generate test model
  • Perform test logic
  • Assert logic

By doing that, your unit test would have a structure like:

@isTest
public class CaseAssignmentTriggerTest{
   static testMethod void testCaseAssignmentTrigger(){
      // Generate test model
      // Perform test logic
      // Assert logic
   }
}

Now, I won't write the code for you, because it won't really help you learn if I do, but I wrote a very detailed article on the proper way to unit test you can take a look at. However, depending on your skill level, you may be better off looking at some Developerforce documentation on "An Introduction to Apex Code Test Methods".

An important thing to note is that there is a 75% code coverage requirement to go to production, but there is also a requirement to have at least 1% of every trigger tested. To test a trigger, we actually have a decent write up by Andrew Fawcett on this site - How to write a unit-test / test class for trigger?

I understand this doesn't actually give you any written code, but hopefully it points you in the right direction to get started. Good luck!

  • Please do not forget to enclose your test logic within a Test.StartTest() and Test.StopTest(). – Programmable Medley Sep 26 '13 at 14:28
  • Yep, you definitely want to do that. That should encapsulate your test logic. – Jesse Altman Sep 26 '13 at 14:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.