I'll admit outright, I'm a beginner when it comes to Apex, so I apologize if anyone's addressed this already or if I'm missing something obvious, but:

I'm trying to write a test class to cover my code on a trigger that I've already determined is executing as I'd like (in our sandbox), but I can't get the test class to pass. The exception it keeps throwing when it fails is "System.QueryException, List has no rows for assignment to SObject."

The line that throws the error is one of the queries (Merchant__c and Location__c are both custom objects, merchant is parent in master-detail relationship). Given that this is the trouble spot, I'm assuming my error is with the bind notation?? But I really don't understand why this wouldn't return anything, especially as I've tested the query in the Developer Console (obviously without the bind notation), and it worked fine.

l3 = [ SELECT Merchant__c FROM Location__c WHERE Name = :locName ];   

To show the whole class, it's

private class testCreateLocationsFromOpportunity {

     static testMethod void myAddLocToExistingMerchantTest() {

        Account a3 = new Account( Name = 'TestAccount3');
        insert a3;

        Contact c3 = new Contact (LastName = 'testdude3', AccountId = a3.Id); 
        insert c3;    

        POS__c p3 = new POS__c (Name  = 'Test POS');
        insert p3;

        Merchant__c m3 = new Merchant__c (Name = 'TestMerchant', merchant_id__c = 1234, Account__c = a3.Id);
        insert m3;

        Opportunity o3 = new Opportunity (Name = 'TestOppty3', Primary_Contact__c = c3.Id, Merchant__c = m3.Id, AccountId = a3.Id, StageName = 'Qualified', Probability = 10);
        insert o3;

        Location_Holder__c lh3 = new Location_Holder__c ( Opportunity__c = o3.Id, Point_of_Sale__c = p3.Id);   
        insert lh3;

        o3.Probability = 100;
        update o3;

        Location__c l3 = new Location__c ();

        String locName = lh3.Name;
        o3 = [ SELECT Merchant__c FROM Opportunity WHERE Name = 'TestOppty3'];
        l3 = [ SELECT Merchant__c FROM Location__c WHERE Name = :locName ];    

        { System.assertEquals(l3.Merchant__c, o3.Merchant__c); }


The trigger I'm looking to cover takes an Opportunity with custom object "Location_Holder__c" related via lookup, and creates custom object Location__c when the Opportunity is Won, porting all the field values from Location_Holder__c to the new Location__c record. What I am testing for here is to make sure that Merchant__r of the new Location__c record is the same Merchant__r on the Opportunity.


FWIW: the name of the location holder is the only field guaranteed to be unique that ports to the location, as opportunities can have multiple location holders that each spin off to their own location.


If your location header name is auto-number or somehow generated automatically in your triggers, you won't have the value in your test class by simply referencing lh3.Name unless you have explicitly specified it in your lh3 record before you insert it.

In this case your record name will be null and you need to re-query it:

lh3 = [SELECT Name FROM Location_Holder__c WHERE Id = :lh3.Id][0];

before you assign it to the string variable:

String locName = lh3.Name;

  • You're right that it's an auto-number! Sorry, meant to say in the post; I've edited now. That's why I didn't state it before inserting lh3; apparently it's a non-writeable field. Added your suggested query, but with where :lh3.id, as it wouldn't let me save without it. Now I'm getting System.QueryException: List has more than 1 row for assignment to SObject. : / – mlpSFadmin Dec 9 '14 at 4:03
  • That does not change anything, just because it's an auto-number, it gets generated after the record has been inserted, which is why you need to query it. Did you try my edited solution? – Boris Bachovski Dec 9 '14 at 4:09
  • I tried the edited version and got the "List has more than 1 row" exception again. I feel like you're right that the thing I'm missing is was querying for the name, but unsure why I'm now getting multiple rows. – mlpSFadmin Dec 9 '14 at 16:38
  • I think you might be getting that error for the other query, double check the line number please – Boris Bachovski Dec 10 '14 at 2:28
  • It's the "l3 =" query line. – mlpSFadmin Dec 10 '14 at 16:20

Assuming that probability 100% means the Opportunity is getting closed and won.

Location__c l3 = new Location__c ();
String locName = lh3.Name;
 o3 = [ SELECT Merchant__c FROM Opportunity WHERE Name = 'TestOppty3'];
 l3 = [ SELECT Merchant__c FROM Location__c WHERE Name = :locName ];    
{ System.assertEquals(l3.Merchant__c, o3.Merchant__c); }

The above patch actually creates a new instance of location and not fetching the one that is created, hence it fails.

I think your lines should be (Assuming Mechant and Location Holder are separate fields) :

 l3 = [ SELECT Merchant__c,Location_Holder__c FROM Location__c WHERE Location_Holder__c = :lh3.Id ]; 
o3 = [ SELECT Merchant__c FROM Opportunity WHERE Name = 'TestOppty3'];
{ System.assertEquals(l3.Merchant__c, o3.Merchant__c); }

So just replacing the lines of 1st patch at the top by 2nd patch above should work!

  • Amit, thanks for your thought! Unfortunately Location_Holder__c isn't a field on Location__c or vice versa. The "relationship" between the two is that we have a trigger that runs when an opportunity closes that sets the Location__c fields equal to the Location_Holder__c fields provided (Location__c has a ton more fields that are used post-opportunity close, the ones from Location_Holder__c are just the necessary ones to get started). – mlpSFadmin Dec 9 '14 at 16:43
  • Sorry, character limit: I think you're onto something with the location__c l3 - new Location__c (); line, though! I was worried the same about creating a new instance vs. fetching the one created in the trigger, but when I took out the line it said I couldn't query for l3 because variable l3 doesn't exist. Is there a different way to fetch the location__c record created in the trigger (which executes at update o3;) so that I can query against it?? – mlpSFadmin Dec 9 '14 at 16:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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