2

I have a trigger that fires when an Active Date is entered on our custom object Location, the trigger updates the Start Date on all child records (Cans) for that Location, so that all of the records then have the same start date. The trigger works when I test it, and the test class runs and does not give any errors, but I still have 0% code coverage. What am I doing wrong?

Here is the code for the trigger

trigger MassUpdateServicesOnActivation on Location__c (after update) 
{
    list<Location__c> locations = new list<Location__c>();

    //find locations where active date is changed
    for(Location__c loc : trigger.new)
    {
        if(loc.Active_Date__c != trigger.oldMap.get(loc.Id).Active_Date__c)
        {
            locations.add(loc);
            System.debug(loc.Name);     //remove
        }
    }

    list<Can__c> cans = new list<Can__C>();
    //query services for each location
    for(Location__c l : locations)
    {
        cans = [SELECT Id, Start_Date__c, Status__c FROM Can__c WHERE Locations__c =: l.Id 
                        AND Status__c = 'Proposed'];

        //update Start Dates
        for(Can__c c : cans)
        {
            c.Start_Date__c = l.Active_Date__c;
        }
    }
    update cans;
}

And here is the test class

@isTest
public class LocationObjectTest {

    public static testMethod void main(){
        //create test data

        Location__c loc = new Location__c();
        //code here add some more required fields to location
        insert loc;

        //create can
        Can__c can = new Can__c();
        can.Locations__c = loc.id;

        insert can;

        //verify that the can and location have been created
        System.assertNotEquals(null, loc.Id);
        System.assertNotEquals(null, can.Id);

        //start test
        Test.startTest();

        loc.Active_Date__c = date.today();
        update loc;
        System.assertEquals(date.today(), loc.Active_Date__c);

        //check that the can has been updated
        list<Can__c> cans = new list<Can__C>();

        cans = [SELECT Id, Start_Date__c FROM Can__c WHERE Locations__c =: loc.Id];

        //check for Start Dates
        for(Can__c c : cans)
        {
            update c;
            System.assertEquals(date.today(), c.Start_Date__c);
            System.assertNotEquals(null, c.Start_Date__c);
            System.debug(c.Start_Date__c);
        }

        Test.stopTest();
    }
}
M Loyd
  • 21
  • 2
  • From your own comments in your test class, it doesn't appear to me that you're providing the required fields needed to create the location. I also recommend you add system.debug statements to you test class to help you discover what's happening to determine if your data is being inserted. See How do I start to debug my own Apex code?. – crmprogdev Oct 09 '15 at 15:02
  • where are you checking the trigger's code coverage ? did u run the test class from the developer console and checked the coverage from the test results ? – Vamsi Krishna Gosu Oct 09 '15 at 15:02
  • Make sure that "Store Only Aggregate Code Coverage" is not check in the Apex Test Execution Options under SF Setup – Eric Oct 09 '15 at 15:19

2 Answers2

0

What sets the can__c.status__c to "Proposed"? you're not creating that record in your unit test with can.status__c = "proposed" so it will not be returned by the query unless some other process does that.

Also, have you confirmed that the location.active_date__c is empty before you update it? One issue could be that the if() condition in your trigger won't fire if the active dates are both today().

On a design note, having the cans query inside your for loop risks hitting a SOQL limit since it will run that query for every qualifiying location record if you update multiples records in the same transaction. It's best to bulkify that by returning the query results to a map before the loop and then referencing the map to get the cans to be updated.

Another bulkification design issue is that you overwrite the cans[] list every time the loop runs, so if you update 2 locations at the same time (e.g. mass edit list view), only the last record will actually get updated because it replaces all previous records updated in cans[]

AlwaysThinkin
  • 1,440
  • 2
  • 16
  • 27
  • The can__c.status__c is a formula field that is set to "Proposed" until a Start Date is entered, then it updates to "Active". The location.active_date__c is empty until I update it, I could add a line of code to verify that this is the case, but I'm not 100% sure how to. Thank you for the bulkification tips, I'm going to do that. – M Loyd Oct 13 '15 at 12:19
  • Validate that it is getting set to Proposed in your unit test since that is a vital criteria in the process. If someone changed the configuration that sets it to Proposed you would want to know it breaks your code. – AlwaysThinkin Oct 13 '15 at 12:22
  • Also, why is there "update c;" in the for loop in your unit test? – AlwaysThinkin Oct 13 '15 at 12:24
0

From the help docs on using the Developer Console to check code coverage:

Checking Code Coverage

The Developer Console retrieves and displays code coverage information from your organization. Code coverage results come from any tests you’ve run from an API or from a user interface (for example, the Developer Console, the Force.com IDE, or the Apex Test Execution page). To clear the current results, click Test | Clear Test Data. When you edit a class, the code coverage for that class is cleared until you run the tests again.

You can view code coverage in several places in the Developer Console.

The Tests tab includes an Overall Code Coverage panel that displays the code coverage percentage for every Apex class in your organization that has been included in a test run. It also displays the overall percentage.

Double-click a completed test run to open a Tests Results view that displays the tested class, the tested method, the duration, result (skip, pass, or fail), and an optional error message. If the test failed, a Stack Trace column shows the method and line number at which the test failed.

To view line-by-line code coverage for an Apex class, open the class. The Code Coverage menu will include one or more of the following options depending on the tests you have implemented:

None

All Tests: The percentage of code coverage from all test runs.

className.methodName: The percentage of code coverage from a method executed during a test run.

Lines of code that are covered by tests are blue. Lines of code that aren’t covered are red. Lines of code that don’t require coverage (for example, curly brackets, comments, and System.debug calls) are left white.

Another doc here for running the tests:

Use the Developer Console to set up test runs, run tests and check Apex code coverage.

The Developer Console Test menu allows you to manage your test runs. It includes the following options:

Always Run Asynchronously: Unless Always Run Asynchronously is enabled, test runs that include tests from only one class run synchronously. Test runs that include more than one class run asynchronously regardless of whether this option is enabled.

New Run: Creates a test run. For details, see Create a Test Run.

Rerun: Runs the test that’s selected in the Tests tab.

Rerun Failed Tests: To rerun only the failed tests from the test run that’s highlighted in the Tests tab, choose this option.

Run All: Runs all saved test runs.

Abort: Aborts the test selected in the Tests tab.

Collapse All: Collapses all open tests in the Tests tab.

Expand All: Expands all tests in the Tests tab.

Clear Test Data: Clears the current test data and code coverage results.

Developer Console Test menu

Completed tests are listed on the Tests tab in the bottom panel of the Developer Console.

In the past sometimes you had to make a small edit and save the trigger then rerun the test to get the coverage, but I haven't run into that in awhile. Try clearing your test data and rerunning make sure you are watching the test tab for any red x's, which is were you would see if your test is passing or failing. I wonder how it would not be failing if you are inserting a record without the required fields?

As a side note: you could accomplish this task with the process builder. If you want to stick with a trigger, watch the bulkification, you have a query inside of your for loop which would cause you to be at risk for hitting the limits.

Jenny B
  • 10,530
  • 3
  • 25
  • 51