Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

I'm having an issue with my Apex Test Class from a trigger. I've used the trigger multiple times in my sandbox but when I try to test it out it fails. The reason for the failure is 'System.QueryException: List has no rows for assignment to SObject' which I have tried to look up but there are so many answers and they don't apply to my certain case. Tried it multiple ways and I am wondering if anybody here has a good answer.

I have two objects, Implementation (custom) and Opportunity. The trigger fires when an Opportunity is set to 'Closed Won'. Below is the trigger:

    trigger CreateImplementation on Opportunity (after update) {

    List<Id> opps = new List<Id>();

    for ( Opportunity opp : Trigger.new ){


        if((opp.StageName == 'Closed Won' ) &&
        (Trigger.oldMap.get(opp.Id).StageName!='Closed Won') ) {

        opps.add(opp.Id);

    }

    Map<Id,Opportunity> oppsMap = new Map<Id,Opportunity>( [SELECT Id, Account.Id, CloseDate, OwnerId, Account.Name from Opportunity where Id IN :opps] );

    List <Implementation__c> impToInsert = new List <Implementation__c> ();

    for( Opportunity oppo : oppsMap.values()){
        Implementation__c imp = new Implementation__c ();

        imp.Account__c = oppo.AccountId;
        imp.Name = oppo.Account.Name +' Implementation';
        imp.Phase__c = 'Phase 0';
        imp.Contract_Date__c = oppo.CloseDate;

        impToInsert.add(imp);
    }

try {
        insert impToInsert;
    } catch (system.Dmlexception e) {
        system.debug (e);
    }
    }
}

And here is the test class

@istest private class CreateImplementation {
    testMethod private static void CreateImplementation () {

        Account acco = new Account(Name = 'Acme Test Account', Type = 'Prospect');
        insert acco;

        Opportunity opp = new Opportunity(Name = 'Acme Test Opp', CloseDate=System.Today(), AccountId=acco.id, Type= 'New Business', Business_Value__c='NA',Closed_Reasons__c='NA', StageName='Closed Won',Amount=1000);
        insert opp;

        Implementation__c imp = [ SELECT Account__c, Name, Phase__c FROM Implementation__c WHERE Account__c = :acco.id LIMIT 1 ];
        System.assertEquals(imp.Phase__c,'Phase 0');
    }
}
share|improve this question
    
Which line of code is generating this error? –  Nick Cook Jun 24 at 23:09

2 Answers 2

up vote 3 down vote accepted

Your trigger is only firing after update and your test does not perform any updates, only the insert of an account and opportunity. Do you intend for Implementation records to be inserted on the insert of a new opportunity? If so, you should make your trigger after insert as well. Alternatively, you can insert the opp and then update it in your test.

The likely reason for your List has no row error is that you are trying to SOQL into a single sObject and not a list and this will throw an error when no rows are returned. In this case, no rows are returned from your Implementation query because of the issue with after update and how you've structured your test.

Instead, try querying into a list of sObject and this will prevent an exception from occurring in your test:

List<Implementation__c> impls = [SELECT...
// And assuming you arrange your test to produce 1 object...
System.assertEquals(1, impls.size());
System.assertEquals('Phase 0', impls[0].Phase__c);
share|improve this answer

Your trigger is an update trigger on the Opportunity object and you are never updating the opportunity in your test class, so an Implementation Object will never be created.

You should be inserting the Opportunity with a Stage other than Closed Won. Then changing the Stage to 'Closed Won'.

Opportunity opp = new Opportunity(Name = 'Acme Test Opp', CloseDate=System.Today(), AccountId=acco.id, Type= 'New Business', Business_Value__c='NA',Closed_Reasons__c='NA', StageName='Some other Stage',Amount=1000);
insert opp;

opp = Select Id, Name From Opportunity Where Id =: opp.Id];
opp.StageName = 'Closed Won';
update opp;

You should also add a check to your trigger code to prevent crashes like this. Right after you create your opps sdt you should check if any of the opps actually fit the criteria, if not your done. So wrap your remaining code in an IF statement

If(!opps.isEmpty()) {    /ADD THIS LINE
    Map<Id,Opportunity> oppsMap = new Map<Id,Opportunity>( [SELECT Id, Account.Id, CloseDate, OwnerId, Account.Name from Opportunity where Id IN :opps] );

    List <Implementation__c> impToInsert = new List <Implementation__c> ();

    for( Opportunity oppo : oppsMap.values()){
        Implementation__c imp = new Implementation__c ();

        imp.Account__c = oppo.AccountId;
        imp.Name = oppo.Account.Name +' Implementation';
        imp.Phase__c = 'Phase 0';
        imp.Contract_Date__c = oppo.CloseDate;

        impToInsert.add(imp);
    }
}  //ADD THIS LINE
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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