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
TBouscalTBouscal 

Test code getting "List has no rows for assignment to SObject" error

Attempting to track down an issue where I get "List has no rows...".
I've added some debug lines to my trigger and what's throwing me for a loop is the message is occuring within the trigger where there is no code and no calls to anything.
if(Trigger.isBefore && Trigger.isInsert){
System.debug('Case.Trigger.isBefore && Case.Trigger.isInsert');         
    }
    if(Trigger.isAfter && Trigger.isUpdate) {
System.debug('Case.Trigger.isAfter && Case.Trigger.isUpdate');
The debug line showing the isBefore && isInsert shows in the log, then the error, then the isAfter && isUpdate.

User-added image

Is there a way, without going through every trigger & class, to track where the issue is occurring?
Best Answer chosen by TBouscal
TBouscalTBouscal
Found my fix.  Within our Case trigger (one trigger per object best practice) my call was within an isInser/isUpdate if statement.  I further qualified it to only run on is update and it doesn't fire on the insert of the test data.  Since the Cases will never be insert as closed this works.
Thanks for all the input folks!

All Answers

Malni Chandrasekaran 2Malni Chandrasekaran 2
TBouscal,
Can you share your complete code? The codes and information you have given may not be sufficient to recreate and fix the issue.
TBouscalTBouscal
Sure think Malni, thanks for taking the time to look
Here's the trigger, do you need to see the test class or class I'm testing?  [SendMail.CaseContact(Trigger.new);]
trigger Cases on Case (after delete, before insert, after insert, after undelete, before update, after update) {

    ParentCaseFlag pcf = new ParentCaseFlag();
    CaseToCtiLink ctcl = new CaseToCtiLink();
    HOL_NA_Escalations hoesc = new HOL_NA_Escalations(); 
   
    
    if(Trigger.isBefore && Trigger.isUpdate){
System.debug('Case.Trigger.isBefore && Case.Trigger.isUpdate');         
        CloseValidation.CheckValidation(Trigger.new,Trigger.oldMap); 
        SetCaseDueDateTime.setDueDateTime(Trigger.old); 
        EscalatedBy.processCase(Trigger.new);

    }
    if(Trigger.isBefore && Trigger.isInsert){
System.debug('Case.Trigger.isBefore && Case.Trigger.isInsert');         
    }
    if(Trigger.isAfter && Trigger.isUpdate) {
System.debug('Case.Trigger.isAfter && Case.Trigger.isUpdate');         
        ctcl.linkUpdate(Trigger.new);
        pcf.processCases(Trigger.old);
        if(Util.isTriggerRunning()==false){
            Util.setTriggerRunning();
            hoesc.processEscalations(Trigger.new);
            hoesc.processEscalationReturns(Trigger.new);
			SendMail.CaseContact(Trigger.new); 
        }
    }
    else if (Trigger.isAfter && Trigger.isDelete) {
System.debug('Case.Trigger.isAfter && Case.Trigger.isDelted');         
        pcf.processCases(Trigger.old);
    }
    else if (Trigger.isAfter && Trigger.isInsert) {
System.debug('Case.Trigger.isAfter && Case.Trigger.isInsert');         
        ctcl.link(Trigger.new);
        pcf.processCases(Trigger.new);
    }
    else if (Trigger.isAfter && Trigger.isUndelete) {
System.debug('Case.Trigger.isAfter && Case.Trigger.isUndelete');         
        pcf.processCases(Trigger.new);
    }
}
Glyn Anderson 3Glyn Anderson 3
Can you post the call stack?  To get it, you can run your test from the Apex Test Execution page.  When it errors, you can view the full exception message, which should include the call stack.

The error should be occurring on a line of code that has the form:

SObject obj = [SELECT Id FROM SObject LIMIT 1];

There's nothing like that in your trigger, so I suspect it's either in the test class or in one of the methods that the trigger calls.  The call stack will tell us exactly (class and line number) where the exception is being thrown.  My guess is that, because the test code does not use "SeeAllData=true", there is something being queried that exists in production, but not in your test.
TBouscalTBouscal
My test doesn't cause any errors, but it doesn't cover all the code yet either.  
It seems part, if not all of the issue, is with the order of execution.  I'm inserting a Case then adding a Task to it to create my test data.  I understand that the after update fires on an insert as well so how do I bypass that while creating my test data so updating the Case will cause the after trigger to fire but creating it will not?
I have to put the call inside the test on line 22 above because I don't want it to fire twice but doing so causes it to fire before the test data is prepared and not fire once the data is prepared.
Malni Chandrasekaran 2Malni Chandrasekaran 2
TBouscal,
If you have not found a solution yet, if my understanding is right, your problem is to bypass trigger while creating a test data.
If yes, you may try,
In your trigger, you may put all your logic under the condition  if Test.isRunningTest() is false.  Let me know if you have already tried it.

Hope this helps!
TBouscalTBouscal
Thank you Malni, however if I opt out of running it while it's in a test then it won't run after the data is created during the test.
I think my answer lies in startTest/stopTest but I can't get beyond a "Method does not exist or incorrect signature: voice startTest() frmo the type test"
 
@isTest static void testSuccess(){
        System.debug('***** Entering SendMailTest2.testSuccess *****');
        Account myAcct = createAccount();
        Contact myCont = createContact(myAcct);
        Case myCase = createCase(myAcct,myCont);         
        // insert a task that doesn't match  
        String theSubj = 'Not a match'; 
        Task myTask = createTask(myCase.id,myCont.id,theSubj); 
        // insert comment
Test.startTest();          
        myCase.Status='Closed';
        Try{
            update myCase;}
        catch (QueryException e){
            System.debug('Error in SendMailTest2 : ' + e.getMessage() + ' - Cause + ' + e.getCause());
        }
Test.stopTest();        

        // Expect 1 new task on Case, total of 2 tasks
		List<Task> newTasks = new List<Task>([SELECT id, whoid, whatid, subject FROM task WHERE whatid = :myCase.id]); 
        for(Task t:newTasks){
            System.debug('testFail -- Task Subject = ' + t.subject); 
        }
        System.assertEquals(2, newTasks.size()); 

        //        System.debug('SOQL queries: ' + Limits.getQueries());  

        System.debug('***** End SendMailTest2.testSuccess *****');
    }

 
TBouscalTBouscal
Found my fix.  Within our Case trigger (one trigger per object best practice) my call was within an isInser/isUpdate if statement.  I further qualified it to only run on is update and it doesn't fire on the insert of the test data.  Since the Cases will never be insert as closed this works.
Thanks for all the input folks!
This was selected as the best answer