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
Mike RethageMike Rethage 

Apex Test Case "For" Statement

Hello,

I have written the following code and have done extensive sandbox testing.  I have several triggers that are very similar but go off of different fields in a contract.  I have a test written for lines 1-12 but can't seem to find the best methodology to writing from line 14 down.  Any help is appreciated.

Code:
trigger Contract_CreateTV_New on Contract (after update){
    System.debug('Contract_CreateTV_New triggered');
    
    Set<Id> activatedContractIds = new Set<Id>();

    for (Contract each : trigger.new) {
        if (each.Status == 'In Progress' && each.RecordTypeId == [Select Id From RecordType WHERE Name = 'Touchtown Contract'].Id && trigger.oldMap.get(each.Id).Status != 'In Progress')
        {
            System.debug('Contract ' + each.Id + ' transitioned into IN PROGRESS status.');
            activatedContractIds.add(each.Id);
            
            if (each.TV_Systems__c != null) {
                                
                for (Integer i = 0; i < each.TV_Systems__c; i++) {
                    Equipment__c newEQPT = new Equipment__c (
                        Account__c = each.AccountId,
                        Name = [Select Name From Account WHERE Id =: each.AccountId].Name,
                        RecordTypeId = [Select Id From RecordType WHERE Name = 'TV+'].Id,
                        Contract__c = each.Id,
                        Product_Type__c = 'TV+',
                        Warranty__c = 'Original (Lifestyle)'
                    );
                    
                    insert newEQPT;
                     List<ContractContactRole> contactRoles = [select ContractId, ContactId from ContractContactRole where Role = 'Install Contact' and ContractId in :activatedContractIds];
    
                    for (ContractContactRole eachRole : contactRoles) {Contract eachContract = trigger.newMap.get(eachRole.ContractId);
                    
                    Junction_Equipment_Contact__c newJunct = new Junction_Equipment_Contact__c(
                        Equipment__c = newEQPT.Id,
                        Contact__c = eachRole.ContactId
                    );
                    
                    insert newJunct;
                    
                    System.debug('Added DS: ' + newEQPT.Id);
                }
            }            
        }
    }
}
}

Test:
@isTest(seealldata=true)
private class TEST_EquipmentCreation {

    static testmethod void TEST_EquipmentCreation()
        
    {
        Account Acct = new Account();
        acct.Name = 'Test Account';
            insert Acct;
                
        Contact Contact = new Contact();
        Contact.FirstName = 'Mike';
        Contact.LastName = 'Test';
        Contact.AccountId = acct.Id;
        Contact.Email = 'test@test.com';
        insert Contact;
        
        Contract newContract = new Contract();
        newcontract.Name = 'test contract';
        newcontract.AccountId = acct.Id;
        newcontract.Status = 'draft';
        newcontract.StartDate = system.today();
        newcontract.RecordTypeId = [Select Id From RecordType WHERE Name = 'Touchtown Contract'].id;
        insert newcontract;
        
        ContractContactRole CCR = new contractContactRole();
        CCR.ContractId = newcontract.Id;
        CCR.ContactId = contact.Id;
        CCR.Role = 'Install Contact';
            insert CCR;
       

        newcontract = [SELECT Status FROM Contract WHERE ID=: newcontract.Id];
        newcontract.status = 'In Progress';
        newcontract.ActivatedDate = system.today();
        update newcontract;
        
     
        newcontract.TV_Systems__c=1;
        update newcontract;
        newcontract.DS_Systems__c=1;
        update newcontract;
       	newcontract.Calendars2__c=1;
        update newcontract;
        newcontract.TTRA_Licenses2__c=500;
        newcontract.Resident_Apps_Level__c = 'Premium';
        newcontract.Web_Shows__c =1;
        newcontract.TTRA_Licenses2__c =500;
        update newcontract;
        
           		for (Integer i = 0; i<newcontract.DS_Systems__c; i++) {
                    Equipment__c newEQPT = new Equipment__c (
                        Account__c = acct.id,
                        Name = acct.Name,
                        RecordTypeId = [Select Id From RecordType WHERE Name = 'Digital Signs'].Id,
                        Contract__c = newcontract.Id,
                        Product_Type__c = 'Digital Sign',
                        Warranty__c = 'Original (Lifestyle)'
                    );
                    
                    insert newEQPT;
                    
                    //List<ContractContactRole> contactRoles = [select ContractId, ContactId from ContractContactRole where Role = 'Install Contact'];
    
                    //for (ContractContactRole eachRole : contactRoles) {Contract eachContract = trigger.newMap.get(eachRole.ContractId);
                    
                    //Junction_Equipment_Contact__c newJunct = new Junction_Equipment_Contact__c(
                        //Equipment__c = newEQPT.Id,
                        //Contact__c = eachRole.ContactId
                    //);
                    
                    //insert newJunct;
                    
                   // System.debug('Added DS: ' + newEQPT.Id);
                 														}     
                //}
        
    } 
    

}

 
pconpcon
I've taken the liberty to rewrite your trigger to make it cleaner and more bulk ready.  This did require splitting out the Junction_Equipment__c creation into a trigger on create of the Equipment__c object.
 
trigger Contract_CreateTV_New on Contract (after update){
    Set<Id> activatedContractIds = new Set<Id>();
    Set<Id> accountIds

    Map<String, RecordType> rtMap = new Map<String, RecordType>();

    for (RecordType rt : [
        select Id
        from RecordType
        where Name = 'Touchtown Contract' or
            Name = 'TV+'
    ]) {
        rtMap.put(rt.Name, rt);
    }

    for (Contract contract : Trigger.new) {
        if (
            contract.RecordTypeId == rtMap.get('Touchtown Contract').Id &&
            contract.Status == 'In Progress' &&
            Trigger.oldMap.get(contract.Id).Status != 'In Progress'
        ) {
            activatedContractIds.add(contract.Id);
            accountIds.add(contract.AccountId);
        }
    }

    if (!activatedContractIds.isEmpty()) {
        Map<Id, Account> accountMap = new Map<Id, Account>([
            select Name
            from Account
            where Id in :accountIds
        ]);


        List<Equipment__c> equipmentToInsert = new List<Equipment__c>();

        for (Contract contract : Trigger.new) {
            if (activatedContractIds.contains(contract.Id)) {
                if (contract.TV_Systems__c != null) {
                    for (Integer i = 0; i < contract.TV_Systems__c; i++) {
                        equipmentToInsert.add(new Equipment__c(
                            Account__c = contract.AccountId,
                            Name = accountMap.get(contract.AccountId).Name,
                            RecordTypeId = rtMap.get('TV+').Id
                            Contract__c = contract.Id,
                            Product_Type__c = 'TV+',
                            Warranty__c = 'Original (Lifestyle)'
                        ));
                    }
                }
            }
        }

        if (!equipmentToInsert.isEmpty()) {
            insert equipmentToInsert;
        }
    }
}
 
trigger ContractJunctionCreate on Equipment__c (after insert) {
    Set<Id> contractIds = new Set<Id>();

    for (Equipment__c e : Trigger.new) {
        contractIds.add(e.Contract__c);
    }

    contractIds.remove(null);

    if (!contractIds.isEmpty()) {
        Map<Id, List<ContractContactRole>> ccrMap = new Map<Id, List<ContractContactRole>>();

        for (Id id : contractIds) {
            ccrMap.put(id, new List<ContractContactRole>());
        }

        for (ContractContactRole ccr : [
            select ContractId,
                ContactId
            from ContractContactRole
            where Role = 'Install Contact' and
                ContractId in :contractIds
        ]) {
            ccrMap.get(ccr.ContractId).add(ccr);
        }  

        List<Junction_Equipment_Contact__c> junctionsToInsert = new List<Junction_Equipment_Contact__c>();

        for (Equipment__c e : Trigger.new) {
            for (ContractContactRole ccr : ccrMap.get(e.Contract__c)) {
                junctionsToInsert.add(new Junction_Equipment_Contact__c(
                    Equipment__c = e.Id,
                    Contact__c = ccr.ContactId
                ));
            }
        }

        if (!junctionsToInsert.isEmpty()) {
            insert junctionsToInsert;
        }
    }
}

As for testing your Equpiment__c insert I would do the following:
 
public class TEST_EquipmentCreation {
    static testMethod void equipmentCreation() {
        Map<String, RecordType> rtMap = new Map<String, RecordType>();

        for (RecordType rt : [
            select Id
            from RecordType
            where Name = 'Touchtown Contract' or
                Name = 'TV+'
        ]) {
            rtMap.put(rt.Name, rt);
        }

        Account testAccount = new Account(
            Name = 'Test Account'
        );
        insert testAccount;

        Contact testContact = new Contact(
            FirstName = 'Mike',
            LastName = 'Test',
            AccountId = testAccount.Id,
            Email = 'test@test.com'
        );
        insert testContact;

        Contract testContract = new Contract(
            Name = 'Test Contract',
            AccountId = testAccount.Id,
            Status = 'draft',
            StartDate = System.today(),
            RecordTypeId = rtMap.get('Touchtown Contract').Id
        );
        insert testContract;

        ContractContactRole testCCR = new ContractContactRole(
            ContractId = testContract.Id,
            ContactId = testContact.Id,
            Role = 'Install Contact'
        );
        insert testCCR;

        Test.startTest();

        testContract.Status = 'In Progress';
        testContract.ActivatedDate = System.today();
        testContract.TV_Systems__c = 3;
        update testContract;

        Test.stopTest();

        List<Equipment__c> results = [
            select Account__c,
                Name,
                RecordTypeId,
                Contract__c
                Product_Type__c,
                Warranty__c
            from Equipment__c
        ];

        System.assertEquals(
            testContract.TV_Systems__c,
            results.size(),
            'Did not get the expected number of equipment records back'
        );

        for (Equipment__c result : results) {
            System.assertEquals(
                testAccount.Id,
                result.Account__c,
                'Did not get the right account id set'
            );

            System.assertEquals(
                testAccount.Name,
                result.Name,
                'Did not get the right name set'
            );

            System.assertEquals(
                rtMap.get('TV+').Id,
                result.RecordTypeId,
                'Did not get the right record type id set'
            );

            System.assertEquals(
                testContract.Id
                result.Contract__c,
                'Did not get the right contract id set'
            );

            System.assertEquals(
                'TV+',
                result.Product_Type__c,
                'Did not get the right product type set'
            );

            System.assertEquals(
                'Original (Lifestyle)',
                result.Warranty__c,
                'Did not get the right warranty set'
            );
        }
    }
}

I would also create a test where you do batch testing and update multiple contracts at the same time to verify that it works correctly.  You'll also want to add tests after the Equipment checks to make sure your junction object was also created as expected.  I would suggest reading over this [1] page to learn more about testing strategies.

[1] http://blog.deadlypenguin.com/blog/testing/strategies/
Mike RethageMike Rethage
Thank you!

I've been sorting through your code and trying to understand it.  I'm getting an error when trying to run it:

Validation Errors While Saving Record(s)
There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger Contract_CreateTV_New_r1 caused an unexpected exception, contact your administrator: Contract_CreateTV_New_r1: execution of AfterUpdate caused by: System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: RecordType.Name: Trigger.Contract_CreateTV_New_r1: line 13, column 1". 

I've tried a number of modifications but after seeing similar cases, I'm not sure I understand why the error.  I've only adjusted the code slightly in a way that should not matter.
 
for (RecordType rt : [
        select Id
        from RecordType
        where Name = 'Touchtown Contract'
            
    ]) {
        rtMap.put(rt.Name, rt);
    }

If I understand the error, is it because we are selecting the ID and then putting the name?  do we need to select the name above in order to enter it?

 
pconpcon
Yeah, sorry that should read
 
for (RecordType rt : [
    select Name
    from RecordType
    where Name = 'Touchtown Contract' or 
        Name = 'TV+'
]) {
    rtMap.put(rt.Name, rt);
}

 
Mike RethageMike Rethage
Thanks again, I'm not sure why that didn't work for me, but I may not have made that change isolated by itself in my testing.

Sorry, but now I'm getting:
Validation Errors While Saving Record(s)
There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger Contract_CreateTV_New_r1 caused an unexpected exception, contact your administrator: Contract_CreateTV_New_r1: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.Contract_CreateTV_New_r1: line 23, column 1". 

but the logic seems correct....
pconpcon
That's most likely because the Name field on the RecordType is incorrect.  If you run the query for RecordType in the developer console, do you get both record types back?
Mike RethageMike Rethage
The Record type label is “Touchtown Contract” but the Name is Touchtown_Contract. I removed the “OR” you had for calling for a record type of TV+ as that is not an option (line 11). I attempted changing the name in your code to Touchtown_Contract and that gave me the same error.
pconpcon
You would need to modify it in several places in the trigger.  The trigger should now look like
 
trigger Contract_CreateTV_New on Contract (after update){
    Set<Id> activatedContractIds = new Set<Id>();
    Set<Id> accountIds

    Map<String, RecordType> rtMap = new Map<String, RecordType>();

    for (RecordType rt : [
        select Name
        from RecordType
        where Name = 'Touchtown_Contract' or
            Name = 'TV+'
    ]) {
        rtMap.put(rt.Name, rt);
    }

    for (Contract contract : Trigger.new) {
        if (
            contract.RecordTypeId == rtMap.get('Touchtown_Contract').Id &&
            contract.Status == 'In Progress' &&
            Trigger.oldMap.get(contract.Id).Status != 'In Progress'
        ) {
            activatedContractIds.add(contract.Id);
            accountIds.add(contract.AccountId);
        }
    }

    if (!activatedContractIds.isEmpty()) {
        Map<Id, Account> accountMap = new Map<Id, Account>([
            select Name
            from Account
            where Id in :accountIds
        ]);


        List<Equipment__c> equipmentToInsert = new List<Equipment__c>();

        for (Contract contract : Trigger.new) {
            if (activatedContractIds.contains(contract.Id)) {
                if (contract.TV_Systems__c != null) {
                    for (Integer i = 0; i < contract.TV_Systems__c; i++) {
                        equipmentToInsert.add(new Equipment__c(
                            Account__c = contract.AccountId,
                            Name = accountMap.get(contract.AccountId).Name,
                            RecordTypeId = rtMap.get('TV+').Id
                            Contract__c = contract.Id,
                            Product_Type__c = 'TV+',
                            Warranty__c = 'Original (Lifestyle)'
                        ));
                    }
                }
            }
        }

        if (!equipmentToInsert.isEmpty()) {
            insert equipmentToInsert;
        }
    }
}

And if the 'TV+' Record Type does not exist you will get problems on line 44 with the same error.