+ Start a Discussion
paddingtonpaddington 

Basic test not working as expected

Hi there,

 

I'm new to this coding lark and am having an issue with a test that is driving me up the wall.

 

I have a basic trigger firing off the insertion of a Contact:

 

trigger ContactInsert on Contact (after insert){ PopulateNotificationContact.updateAccount(Trigger.new); }

 This calls a class that populates a custom contact lookup on the Account called Notification_Contact__c with the ID of the inserted contact, if Notification_Contact__c is null:

 

 

public with sharing class PopulateNotificationContact { public static void updateAccount(Contact[] cons){ for(Contact c:cons){ string s=c.AccountId; Account a=[select Id, Notification_Contact__c from Account where Id=:s]; if(a.Notification_Contact__c==null){ a.Notification_Contact__c=c.Id; update a; } } } }

 This all works fine, which is great, although I suspect that I'm not writing very good code. Whatever, I want to get it into live, so have written the following test class, which is where the problem is:

 

 

public class TEST_PopulateNotificationContact{ static testMethod void testInitialEnquiry(){ Account a = new Account(name = 'Acme'); insert a; //Assert that Notification_Contact__c is null System.assertEquals(a.Notification_Contact__c,null); // Inserting the record automatically assigns a value to its ID field Contact c = new Contact(LastName = 'Coyote'); c.accountId = a.Id; // The new contact now points at the new account insert c; //Inserting the contact fires the InitialEnquiryTrue trigger, which should populate //the Notification_Contact__c field System.assertEquals(a.Notification_Contact__r.Id,c.Id,'IDs not the same.'); } }

 The second assert is trying to prove that inserting a new contact on the Acme account populates the Notification_Contact__c field, but the following error is returned:

 

System.Exception: Assertion Failed: IDs not the same.: Expected: null, Actual: 003S0000005UplTIAS

 

I'm sure that I'm making a schoolboy error, but can't work it out. Any ideas would be much appreciated.

 

Thanks,

 

Joe

 

 

 

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
WesNolte__cWesNolte__c

Hey

 

You are receiving this error because your execution flow is something like this,

 

Set Account details and put them in a variable.

Insert account.(You now have a local copy of the Account stored in 'memory')

 

Set contact details.

Insert contact. (Account object in Database is updated, but your local varibale is not updated) 

 

You'd need to fetch the account object from the database after the contact insert in order to retrieve it's updated values.

 

A quick efficiency tip, slightly off-topic, you might want to refactor this code:

 

 

for(Contact c:cons){

string s=c.AccountId;

Account a=[select Id, Notification_Contact__c from Account where Id=:s]; if(a.Notification_Contact__c==null){

a.Notification_Contact__c=c.Id;

update a; } 

}

 

 You should never put a query inside of a loop. It might not give you errors now, but if your dataset grows(and it always does) you will hit governor limits.

 

This article should help you fix it up.

 

Cheers,

Wes 

Message Edited by weznolte on 10-27-2009 01:12 PM
Message Edited by weznolte on 10-27-2009 01:18 PM

All Answers

WesNolte__cWesNolte__c

Hey

 

You are receiving this error because your execution flow is something like this,

 

Set Account details and put them in a variable.

Insert account.(You now have a local copy of the Account stored in 'memory')

 

Set contact details.

Insert contact. (Account object in Database is updated, but your local varibale is not updated) 

 

You'd need to fetch the account object from the database after the contact insert in order to retrieve it's updated values.

 

A quick efficiency tip, slightly off-topic, you might want to refactor this code:

 

 

for(Contact c:cons){

string s=c.AccountId;

Account a=[select Id, Notification_Contact__c from Account where Id=:s]; if(a.Notification_Contact__c==null){

a.Notification_Contact__c=c.Id;

update a; } 

}

 

 You should never put a query inside of a loop. It might not give you errors now, but if your dataset grows(and it always does) you will hit governor limits.

 

This article should help you fix it up.

 

Cheers,

Wes 

Message Edited by weznolte on 10-27-2009 01:12 PM
Message Edited by weznolte on 10-27-2009 01:18 PM
This was selected as the best answer
David VPDavid VP

You create an Account object (in memory), you do some updates to the database (where the trigger does it's work).

Your assert compares the in-memory values of the Account, not what happened 'down below' in the db.

 

 You need to query the database values for the account values back into your test class to see if it correctly updated the db.

 

 

//Inserting the contact fires the InitialEnquiryTrue trigger, which should populate //the Notification_Contact__c field Account atest = [select a.Notification_Contact__r.Id from Account where a.Id = :a.Id]; System.assertEquals(a.Notification_Contact__r.Id,c.Id,'IDs not the same.');

 

 

 

BritishBoyinDCBritishBoyinDC

Couple of things to try...

 

When you use system.assertequals, the value you are comparing against comes first so:

 

System.assertEquals(null, a.Notification_Contact__c);

 

Second, when you insert a record, you need to re-query for it when using in an assert:

 

 

public class TEST_PopulateNotificationContact{ static testMethod void testInitialEnquiry(){ Account a = new Account(name = 'Acme'); insert a; //Assert that Notification_Contact__c is null Account testa = [Select Id, Name, Notification_Contact__c from Account where Id = :a.Id]; System.assertEquals(null, testa.Notification_Contact__c);

 

 Try that, and for the subsequent Contact create record, and see it it helps...

 

 

 

 

 

paddingtonpaddington

Thanks to Wes, David and BritishBoyinDC. Like I said, schoolboy.

 

Particular thanks to Wes, as I spent an hour re-factoring the code in the main class with that article as guidance and I hope that I've got something that is closer to best practice:

 

 

public with sharing class PopulateNotificationContact {

public static void updateAccount(List<Contact> cons){

//Intermediate list for updating
List<Account> accsToUpdate = new List<Account> ();

//Create list of account IDs referenced by contacts
List<ID> refAccs = new List<ID> ();
for (Contact c:cons){
refAccs.add(c.AccountId);
}

//Query accounts for notification contacts and put in a map
Map<ID,Account> Accounts = new Map<ID,Account>([SELECT Id, Notification_Contact__c FROM Account where Id IN :refAccs]);

for(Contact c:cons){

//Define account in question
Account a = Accounts.get(c.AccountId);

//If the notification contact field is empty
if(a.Notification_Contact__c==null){

//Fill it with the inserted contact
a.Notification_Contact__c=c.Id;

//Add processed object to intermediate list
accsToUpdate.add(a);
}
}

//Update all objects at once
update accsToUpdate;
}
}

 

Any comments? It seems to work fine and the test runs okay, although declaring the map screwed with my head a bit.

 

As for the test class, now I understand this whole memory/database thing it all makes sense:

 

 

public class TEST_PopulateNotificationContact{

static testMethod void testInitialEnquiry(){

//Create a new account
Account a = new Account(name = 'Acme');
insert a;

//Assert that Notification_Contact__c is null
Account testa = [Select Notification_Contact__c from Account where Id = :a.Id];
System.assertEquals(null, testa.Notification_Contact__c);

//Create a new contact at the new account
Contact c = new Contact(LastName = 'Coyote');
c.accountId = a.Id;
insert c;

//Inserting the contact fires the InsertContact trigger, which should call the
//PopulateNotificationContact class, which populates the Notification_Contact__c field
Account testb = [Select Notification_Contact__r.Id from Account where Id = :a.Id];
System.assertEquals(c.Id,testb.Notification_Contact__r.Id,'IDs do not match');
}
}

 Thanks again for the support guys.

 

Joe

 

 

 

 

Message Edited by paddington on 10-27-2009 11:18 AM
WesNolte__cWesNolte__c

Looks good:) It is a bit tricky to get your mind around the first few times, but soon you'll be a programming hax0r(this is a good thing).