+ Start a Discussion
John NeilanJohn Neilan 

Increase Test Coverage

Hello,

I have a trigger handler class below that fires on a Task event and updates custom checkbox fields on the Opportunity object based on a few variables in the Task record.  The trigger fires as appropriate, however, I am having difficulty getting coverage on lines 39 - 50 with the test class I have below (specifically lines 58 - 75 to cover that portion of the trigger).  Can anyone give me guidance on how I can cover these lines?

Handler Class:
public void renewalTasks(List<Task> checkTasks) {

            List<Opportunity> linkedOpps = new List<Opportunity>();
            Map<Id, Task> taskMap = new Map<Id, Task>();

            for (Task t: checkTasks) {

                if (t.WhatId  != null && (t.Subject == 'User Training Complete' ||
                                        t.Subject == 'Initial Program Confirmation' ||
                                        t.Subject == 'Renewal Package Review')){
                    taskMap.put(t.WhatId, t);
                }
            }

            if (taskMap.size() > 0)
            {
                linkedOpps = [SELECT Account.Id, Effective_Date__c, Renewal_Date_Next__c, RP_User_Training__c,
                                    RP_Initial_Program_Developed__c,
                                    RP_Recommendation_Review_Call__c
                                FROM Opportunity 
                                WHERE Account.Id IN: taskMap.keySet() AND IsClosed =: FALSE];

                for (Opportunity c: linkedOpps){

                    for (Task taskAdd:[SELECT WhatId, Subject, Status, ActivityDate
                                        FROM Task
                                        WHERE WhatId =: c.Account.Id]){
                    IF(taskAdd.Status == 'Completed' && taskAdd.ActivityDate >= c.Effective_Date__c && taskAdd.ActivityDate <= c.Renewal_Date_Next__c){
                        IF(taskAdd.Subject == 'User Training Complete' && taskAdd.Status == 'Completed'){
                            c.RP_User_Training__c = TRUE;
                        }
                        IF(taskAdd.Subject == 'Initial Program Confirmation'){
                            c.RP_Initial_Program_Developed__c = TRUE;
                        }
                        IF(taskAdd.Subject == 'Renewal Package Review'){
                            c.RP_Recommendation_Review_Call__c = TRUE;
                        }
                    }
                    ELSE IF((taskAdd.Status != 'Completed' && taskAdd.ActivityDate >= c.Effective_Date__c && taskAdd.ActivityDate <= c.Renewal_Date_Next__c) ||
                            (taskAdd.Status == 'Completed' && (taskAdd.ActivityDate < c.Effective_Date__c || taskAdd.ActivityDate > c.Renewal_Date_Next__c)) ||
                            (taskAdd.Status != 'Completed' && (taskAdd.ActivityDate < c.Effective_Date__c || taskAdd.ActivityDate > c.Renewal_Date_Next__c))){

                        IF(taskAdd.Subject == 'User Training Complete'){
                            c.RP_User_Training__c = FALSE;
                        }
                        IF(taskAdd.Subject == 'Initial Program Confirmation'){
                            c.RP_Initial_Program_Developed__c = FALSE;
                        }
                        IF(taskAdd.Subject == 'Renewal Package Review'){
                            c.RP_Recommendation_Review_Call__c = FALSE;
                        }
                    }
                    }
                }

                if (linkedOpps.size() > 0)
                {
                update linkedOpps;
                }
            }
        }

Test Class:
@isTest
public class TestRenewalTasks{

    static testmethod void testRenewalTasks(){

        Profile ProSys = [SELECT Id
                          FROM Profile
                          WHERE Name='Client Services (Admin)'];
        User U1 = new User(Alias = 'User1',Country='United States',Email='User1@testing.com',EmailEncodingKey='ISO-8859-1', LastName='User1', 
                            LanguageLocaleKey='en_US',LocaleSidKey='en_US',ProfileId = ProSys.Id,TimeZoneSidKey='America/New_York', UserName='User1@testing.com');
        insert U1;


        Account acct1 = new Account();
        acct1.Name = 'Test-JN';
        acct1.Region__c = 'USA';
        acct1.BillingCountry = 'USA';
        acct1.Industry = 'Consumer Goods';
        acct1.Status__c = 'Customer';
        acct1.Website = 'www.test.com';
        acct1.FB_Page_1_Fans__c = 500;
        acct1.FB_Page_1_Link__c = 'www.facebook.com/test';
        acct1.OwnerId = U1.Id;
        INSERT acct1;

        Opportunity opp1 = new Opportunity();
        opp1.Name = 'Test-JN Renewal Opp';
        opp1.StageName = 'Phase 1: Planning & Training';
        opp1.CloseDate = date.parse('1/1/15');
        opp1.Renewal__c = 'Yes';
        opp1.Effective_Date__c = date.parse('1/1/15');
        opp1.Term__c = 12;
        opp1.AccountId = acct1.Id;
        INSERT opp1;

    Test.startTest();

    List<Task> tasklist = new List<Task>();
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Initial Program Confirmation',
            Status = 'Completed', Priority = 'Normal'));
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop User Training Complete',
            Status = 'Completed', Priority = 'Normal'));
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Primary Goal Training Confirmation',
            Status = 'Completed', Priority = 'Normal'));
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Initial Campaign Results',
            Status = 'Completed', Priority = 'Normal'));
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Business Review',
            Status = 'Completed', Priority = 'Normal'));
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Roadmap Review',
            Status = 'Completed', Priority = 'Normal'));
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Manager Introduction',
            Status = 'Completed', Priority = 'Normal'));
        taskList.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Renewal Package Review',
            Status = 'Completed', Priority = 'Normal'));
        INSERT taskList;
        DELETE taskList;

    List<Task> tasklist2 = new List<Task>();
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Initial Program Confirmation',
            Status = 'In Progress', Priority = 'Normal'));
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop User Training Complete',
            Status = 'In Progress', Priority = 'Normal'));
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Primary Goal Training Confirmation',
            Status = 'In Progress', Priority = 'Normal'));
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Initial Campaign Results',
            Status = 'In Progress', Priority = 'Normal'));
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Business Review',
            Status = 'In Progress', Priority = 'Normal'));
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Roadmap Review',
            Status = 'In Progress', Priority = 'Normal'));
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Manager Introduction',
            Status = 'In Progress', Priority = 'Normal'));
        taskList2.add(new Task(WhatId = acct1.Id, ActivityDate = date.parse('1/5/15'), Subject = 'Offerpop Renewal Package Review',
            Status = 'In Progress', Priority = 'Normal'));
        INSERT taskList2;
    Test.stopTest();

    }
}

 
pconpcon
I would break down what you have into a bunch of smaller tests.  I would write several tests that operate on only a single task and then evaluate the change.  Then have a test that handles bulk changes (and I would split out my tests for one insert, one delete and one insert).

One test I would have a task that meets all the criteria on line 28  and line 29, but not 32 or 35.  The one that meets the criteria on line 28 and line 32 but not 29 and 35 and so on.  Then create another test that does not meet the criteria on line 28 but does meet the first set of criteria on line 39 and line 43 but not 46 and 49.

You will end up with a lot of permuations, but it is the only real way to be sure that your code is doing exactly as you expect.  Additionally, you should (after your Test.stopTest() query back your Opportunity objects and check to make sure that the fields you set are as you want.

Each test should follow the following structure:
  • Setup of test data. This includes creation of any data needed by your class.  Account, Contacts etc
  • Starting the test. This is calling Test.startTest() to reset the governor limits
  • Calling your class / method
  • Stopping the test. This is calling Test.stopTest() to reset the governor limits and allow for any async jobs to finish
  • Asserting that your changes have worked
    • If you have inserted/updated/deleted data, you need to query for the updates
    • Run System.assert, System.assertEquals, System.assertNotEquals to verify that you got the correct data back
You are covering the first couple of steps pretty well, but you are missing the asserts and you really should break this down into smaller tests.  Writing utility methods [1] to handle your test data (such as creating your test user, test account and test opportunity) will make this much easier.

If you have any specific questions please, let me know.

[1] http://pcon.github.io/presentations/testing/#testutils-list3
John NeilanJohn Neilan
I get what you are saying, but I really just need to figure out the syntax for testing when an update occurs to one of my inserted tasks that brings it to meeting the criteria on lines 39-41 rather than Line 28.  There would not be 2 tasks with the same subject.  The trigger either checks the box on the Opp if the task meets the criteria on line 28, or unchecks it if the criteria on lines 39-41 is met.  I just can't figure out how to write the portion of the test to check for the change rather than an insert.
pconpcon
I have taken the liberty to update your code to make it more readable as well as more able to handle bulk operations.
 
public void renewalTasks(List<Task> checkTasks) {
    List<Opportunity> linkedOpps = new List<Opportunity>();
    Map<Id, Task> taskMap = new Map<Id, Task>();
    Map<Id, List<Task>> accountToTaskMap = new Map<Id, List<Task>>();

    for (Task t: checkTasks) {
        if (
            t.WhatId  != null &&
            (   
                t.Subject == 'User Training Complete' ||
                t.Subject == 'Initial Program Confirmation' ||
                t.Subject == 'Renewal Package Review'
            )
        ) { 
            taskMap.put(t.WhatId, t);
            accountToTaskMap.put(t.WhatId, new List<Task>());
        }
    }

    if (!taskMap.isEmpty()) {
        linkedOpps = [
            select AccountId,
                Effective_Date__c,
                Renewal_Date_Next__c,
                RP_User_Training__c,
                RP_Initial_Program_Developed__c,
                RP_Recommendation_Review_Call__c
                from Opportunity
                where AccountId in :taskMap.keySet() and
                    IsClosed = false
        ];

        // To be perfectly honest, I'm not sure why you are getting all the tasks
        //   for the accounts and not sorting by something like activity date
        //   since you're likely to overwrite the fields
        for (Task t : [
            select WhatId,
                Subject,
                Status,
                ActivityDate
            from Task
            where WhatId = :taskMap.keySet()
        ]) {
            accountToTaskMap.get(t.WhatId).add(t);
        }

        for (Opportunity c: linkedOpps) {
            for (Task taskAdd : accountToTaskMap.get(c.AccountId)) {
                if (
                    taskAdd.Status == 'Completed' &&
                    taskAdd.ActivityDate >= c.Effective_Date__c &&
                    taskAdd.ActivityDate <= c.Renewal_Date_Next__c
                ) { 
                    if (
                        taskAdd.Subject == 'User Training Complete' &&
                        taskAdd.Status == 'Completed'
                    ) { 
                        c.RP_User_Training__c = true;
                    }

                    if (taskAdd.Subject == 'Initial Program Confirmation') {
                        c.RP_Initial_Program_Developed__c = true;
                    }

                    if (taskAdd.Subject == 'Renewal Package Review') {
                        c.RP_Recommendation_Review_Call__c = true;
                    }
                } else if (
                    (   
                        taskAdd.Status != 'Completed' &&
                        taskAdd.ActivityDate >= c.Effective_Date__c &&
                        taskAdd.ActivityDate <= c.Renewal_Date_Next__c
                    ) || (
                        taskAdd.Status == 'Completed' &&
                        (
                            taskAdd.ActivityDate < c.Effective_Date__c ||
                            taskAdd.ActivityDate > c.Renewal_Date_Next__c
                        )
                    ) || (
                        taskAdd.Status != 'Completed' &&
                        (
                            taskAdd.ActivityDate < c.Effective_Date__c ||
                            taskAdd.ActivityDate > c.Renewal_Date_Next__c
                        )
                    )
                ) {
                    if (taskAdd.Subject == 'User Training Complete'){
                        c.RP_User_Training__c = false;
                    }

                    if (taskAdd.Subject == 'Initial Program Confirmation'){
                        c.RP_Initial_Program_Developed__c = false;
                    }

                    if (taskAdd.Subject == 'Renewal Package Review'){
                        c.RP_Recommendation_Review_Call__c = false;
                    }
                }
            }
        }

        if (!linkedOpps.isEmpty()) {
            update linkedOpps;
        }
    }
}

Based on this class, this would be an example test that should reach into the else statement of your method.  Note that we are using Date.today().addDays(Integer) to manipulate the days so that it will continue to work regardless of when the tests are run
 
static testMethod void testNonCompletedTask() {
    Profile csAdminProfile = [
        select Id
        from Profile
        where NAme = 'Client Services (Admin)'
    ];  

    User testUser = new User(
        Alias = 'User1',
        Country = 'United States',
        Email = 'User1@testing.com',
        EmailEncodingKey = 'ISO-8859-1',
        LastName = 'User1',
        LanguageLocaleKey = 'en_US',
        LocaleSidKey = 'en_US', 
        ProfileId = csAdminProfile.Id,
        TimeZoneSidKey = 'America/New_York',
        UserName = 'User1@testing.com'
    );  
    insert testUser;
        
    Account testAccount = new Account(
        Name = 'Test-JN',
        Region__c = 'USA',
        BillingCountry = 'USA',
        Industry = 'Consumer Goods',
        Status__c = 'Customer',
        Website = 'www.test.com',
        FB_Page_1_Fans__c = 500,
        FB_Page_1_Link__c = 'www.facebook.com/test',
        OwnerId = testUser.Id
    );  
    insert testAccount;

    Opportunity testOpportunity = new Opportunity(
        Name = 'Test-JN Renewal Opp',
        StageName = 'Phase 1: Planning & Training',
        CloseDate = Date.today().addDays(5),
        Renewal__c = 'Yes',
        Effective_Date__c = Date.today().addDays(-5),
        Renewal_Date_Next__c = Date.today().addDays(5),
        Term__c = 12,
        AccountId = testAccount.Id,
        RP_User_Training__c = true,
        RP_Initial_Program_Developed__c = true,
        RP_Recommendation_Review_Call__c = true
    );      
    insert testOpportunity;
      
    Task testTask = new Task(
        WhatId = testAccount.Id,
        Subject = 'User Training Complete',
        Status = 'Incomplete',
        ActivityDate = Date.today()
    );  

    Test.startTest();

    // I'm making an assumption that inserting this test
    //   task will infact call your renewalTasks method
    insert testTask;

    Test.stopTest();

    testOpportunity = [
        select RP_User_Training__c,
            RP_Initial_Program_Developed__c,
            RP_Recommendation_Review_Call__c
        from Opportunity
        where Id = :testOpportunity.Id
    ];

    System.assert(
        !testOpportunity.RP_User_Training__c,
        'The user training flag should have been cleared'
    );

    System.assert(
        !testOpportunity.RP_Initial_Program_Developed__c,
        'The initial program flag should not have been cleared'
    );

    System.assert(
        !testOpportunity.RP_Recommendation_Review_Call__c,
        'The recommendation review flag should have been cleared'
    );
}

NOTE: This code has not been tested and may contain typographical or logical errors.