1

First, let me say that I did not write most of the code below. I am trying to deploy additional Apex code and this code, written by my predecessor, is failing Apex tests when I try to deploy my change set to Production, apparently because "List has no rows for assignment to SObject".

So I hopped on Google and found this solution:

https://help.salesforce.com/HTViewSolution?id=000159853&language=en_US

which I tried to adapt to the code, but now I am getting an error message "Compile Error: Expression must be a list type: Engagement__c at line 21 column 21"

line 21 below is the line " testE = test E[0].Id; "

Can anyone guide me to a solution? Thanks in advance

@isTest(SeeAllData=true)

public class testBlockDuplicateTeamMembers {

static testMethod void testBlockDuplicateTeamMembers(){

    Profile p = [SELECT Id FROM Profile WHERE Name='System Administrator'];
    User u = new User(Alias='testUser', email='testUser@mycompany.com',
        EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US', 
        LocaleSidKey='en_US', ProfileId = p.Id, 
        TimeZoneSidKey='America/Los_Angeles', UserName='testuser@mycompany.com', Can_Closed_Booked_Opportunities__c = TRUE); 
    insert u;

    u = [SELECT Id FROM User WHERE UserName='testuser@mycompany.com' LIMIT 1];

    System.runAs(u){

        Engagement__c testE = [SELECT Id FROM Engagement__c WHERE Status__c = 'New' LIMIT 1];

        if(testE.size() > 0)
        testE = testE[0].Id;
  • 1
    Don't use SeeAllData=true. Create your data. – Adrian Larson Aug 25 '16 at 22:33
  • 2
    Please don't try to do a patch, the code is screaming for help already with seealldata=true. If you really care about deploying the code only, go create a Engagement record with Status = new in the target org. Do not modify anything in the code – Rao Aug 25 '16 at 22:33
  • Yes, they are a lot of really messed up things in this org. I took over as Senior Admin about two months ago and I find something head-shaking every day. @Rao I will take your suggestion and run with it. Thanks! – GSquared Aug 25 '16 at 22:40
  • Follow Up: When I tried to create a new record, realized the picklist choices had been modified from 'New" to "10-New". So I modified the code to reflect that. – GSquared Aug 25 '16 at 22:44
4

To the specific compiling problem from the question rather than the larger problems with how the test is running.

Engagement__c testE = [SELECT Id FROM Engagement__c WHERE Status__c = 'New' LIMIT 1];

if(testE.size() > 0)
    testE = testE[0].Id;

In the first line of this snippet testE is declared as a variable of type Engagement__c.

Then in the last line of the snippet the code tries to access the first element of the collection and assign the Id field from that back to the testE variable.

The problem with this is that testE isn't a List or Set that represents a collection. I.e. It is just a single Engagement__c instance rather than List<Engagement__c>. The other problem is that you can't assign an Id to a Engagement__c type.

Something like the following would make more sense:

List<Engagement__c> newEngagements = [SELECT Id FROM Engagement__c WHERE Status__c = 'New' LIMIT 1];

if(newEngagements.size() > 0) {
    Id idOfNewEngagement  = newEngagements[0].Id;
    // ...
} else {
    System.assert(false, 'Expected at least one Engagement for valid test execution');
}

However, as both Adrian and Rao have commented, the general idea of querying for an existing Engagement__c record using @SeeAllData=true is a really bad.

What happens to your test if that record doesn't exist in production currently? As you found out with the original code, you get a List has no rows for assignment to SObject error is you assume the SOQL query will return at least one record.

It might be there one day and then gone the next. Much better to script in all the data that your test depends on so it will work consistently regardless of the current state of the data in the org.

See also:

| improve this answer | |
  • 1
    I agree that your second code sample is the standard way to query for a single record you don't know will exist. In the context of a unit test, however, it might make more sense to use system.assert(!newEngagements.isEmpty()). Because otherwise a "passing" test may fool you in a kind of nefarious way. – Adrian Larson Aug 26 '16 at 1:24
  • 1
    @AdrianLarson Fair point. I've gone with a false assertion so it is still clear what the more standard pattern is after making a SOQL query. – Daniel Ballinger Aug 26 '16 at 2:29

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.