I have created a class that looks for email attachments for closed cases. My goal is to delete those attachments. The issue I am having is that I am unable to get to %100 code coverage. My execute method does not get any coverage. Any guidance would be greatly appreciated.

Here is my class:

global class HarveyAttachmentDeleteBatch implements Database.Batchable<sObject>, Database.Stateful {

    global Set<Id> setAttachmentIds = new Set<Id>();
    public String atts;
    private date querydate;

    global Integer recordsProcessed = 0;

    public HarveyAttachmentDeleteBatch (date startdate){

       querydate = startdate;


    global Database.QueryLocator start(Database.BatchableContext att){
        return Database.getQueryLocator(
                                        'Select id '+ 
                                        'From EmailMessage '+ 
                                        'Where HasAttachment = true AND ParentId IN (Select Id ' +
                                                                                    'From Case '+
                                                                                    'Where ClosedDate < :querydate '+
                                                                                    'AND RecordType.Name = \'Hurricane Harvey\')'


    global void execute(Database.BatchableContext att, List<EmailMessage> scope){
        // List<Attachment> attachments = new List<Attachment>();
        for (EmailMessage objEmailMessage : scope) {
            if (objEmailMessage.attachments != null && objEmailMessage.attachments.size() > 0){
                for (Attachment objAttachment:objEmailMessage.attachments){


        atts = 'select Id from Attachment Where Id in :setAttachmentIds';

        List<Attachment> attlist = database.query(atts);
        if(attlist != null){
                delete attlist;
            } catch(Exception e){}


    global void finish(Database.BatchableContext att){


Here is my test Class:

private class HarveyAttachmentDeleteBatchTest {

    static void setup() {
        //Date d = Date.Today().adddays(1);
        List<EmailMessage> emailmessages = new List<EmailMessage>();
        List<Case> cases = new List<Case>();
        List<Attachment> attachments = new List<Attachment>();

        Id casetype = schema.SObjectType.Case.getrecordTypeInfosByName().get('Hurricane Harvey').getRecordTypeId();

        //insert 10 cases
        for (Integer i=0;i<10;i++){
            cases.add(new Case(RecordTypeId = casetype, Status = 'Closed - Paid', Subject = 'Test '+ i));
            // cases.add(new Case(RecordTypeId = casetype, Subject = 'Test '+ i));

        insert cases;
        System.debug('Cases:' + cases.size());

        //find the Cases and insert email messages for each
        for (Case casemsg : [select id from case]){
            emailmessages.add(new EmailMessage(Subject= 'Test Email Subject', HTMLBody= 'Test Email Body', 
                                               FromAddress= 'Test@email.com', parentId = casemsg.id));  

        insert emailmessages;
        System.debug('Email Messages:' + emailmessages.size());

        // find the Emails and insert attachments for each
        for (EmailMessage emmsg : [select id from EmailMessage]){
            attachments.add(new Attachment(Name = 'Unit Test Attachment', Body= Blob.valueOf('Unit Test Attachment Body'),
                                           parentId = emmsg.id));
        insert attachments;

        System.debug('Attachments:' + attachments.size());


    static testmethod void test(){


        Date d = Date.Today().adddays(1);

        Case[] ca  = [Select id, ClosedDate From Case Where IsClosed= True AND RecordType.Name = 'Hurricane Harvey' AND ClosedDate <: d];
        System.debug('ca: ' + ca);
        EmailMessage[] em = [Select id From EmailMessage Where HasAttachment = True AND parentId IN : ca];
        Attachment[] ematt = [Select id  From Attachment Where parentId IN :em];
        System.assertEquals(10, ematt.size());

        HarveyAttachmentDeleteBatch had = new HarveyAttachmentDeleteBatch(d);
        Id batchId = Database.executeBatch(had);

        delete ematt;

        Case[] ca2  = [Select id From Case Where IsClosed= True AND RecordType.Name = 'Hurricane Harvey' AND ClosedDate <: d];
        EmailMessage[] em2 = [Select id From EmailMessage Where HasAttachment = True AND parentId IN : ca2];
        Attachment[] ematt2 = [Select id  From Attachment Where parentId IN :em2];
        System.assertequals(0, ematt2.size());


  • I would suggest looking over this trailhead. It should provide what you are looking for : trailhead.salesforce.com/en/modules/asynchronous_apex/units/… Nov 16 '17 at 19:29
  • Thank you for the recommendation. That is exactly what I have been using. I think my problem may be in my queryLocator in my Batch class. I think when i am creating test records, maybe the HasAttachment field does not get set to TRUE right away. Not sure how to resolve for that.
    – Ivo Dimov
    Nov 16 '17 at 20:34
  • What part of your code is not covered by your test class when you do a run? Nov 16 '17 at 21:15
  • 1
    The batch class won't execute until the test.stoptest() so you need to be querying for records and asserting they were deleted after Test.stoptest()
    – cropredy
    Nov 17 '17 at 2:23

Didn't look at the test, but the batchable would need to look more like this to work:

public class HarveyAttachmentDeleteBatch implements Database.Batchable<sObject>{

    private Date queryDate;

    public HarveyAttachmentDeleteBatch(Date queryDate){
        this.queryDate = queryDate;

    public Database.QueryLocator start(Database.BatchableContext bc){
        return Database.getQueryLocator([
                Select Id, (Select Id from Attachments)
                From EmailMessage
                Where HasAttachment = true
                AND ParentId IN
                        Select Id
                        From Case
                        Where ClosedDate < :querydate
                        AND RecordType.Name = 'Hurricane Harvey'

    public void execute(Database.BatchableContext bc, List<EmailMessage> scope) {
        Map<Id, Attachment> m = new Map<Id, Attachment>();
        for (EmailMessage em : scope) {
            for (Attachment a : em.Attachments){
                m.put.add(a.Id, new Attachment(Id = a.Id)); 
        delete m.values();

    public void finish(Database.BatchableContext att){

Changes I've made are:

  • Querying the attachments in the query in the start method (as the code won't work without that)
  • Not having catch(Exception e){} which is almost always a bad idea in that it hides errors that you normally need to see
  • Using static (compile-time checked) SOQL to reduce the chances of query syntax errors
  • Removing unnecessary code
  • -

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.