You need to sign in to do that
Don't have an account?
Jewelyn Fregoe
an anyone help fix my Apex Class for my Trigger that posts to a Chatter group each time an Opp Status changes?
I'm still new to writing triggers/Apex Classes, so I think I may have taken on something a bit too complicated for my first one. Any help is appreciated!
Here's my Apex Trigger. I have it in my sandbox and it does work! Everytime an opportunity's status changes, a post is made in a group chatter.
trigger trgr_CreateChatterGroupAlerts on Opportunity (after Update) {
List<Opportunity> updatedOpptyList =
[
SELECT
Id,
Name,
Account.Name,
StageName,
LastModifiedBy.Name
FROM
Opportunity
WHERE
Id IN :trigger.newMap.keyset()
];
String changedOpptyList = '';
for(Opportunity oppty : updatedOpptyList){
if(oppty.StageName != trigger.oldMap.get(oppty.Id).StageName){
changedOpptyList +=
'Opportunity ' + oppty.Name + ' (' + oppty.Account.Name + ')'+
' has its Stage changed from ' + trigger.oldMap.get(oppty.Id).StageName + ' to ' +
oppty.StageName + '\r\n';
}
}
if(changedOpptyList!=''){
FeedItem feedItem = new FeedItem();
feedItem.ParentId = System.Label.Opportunity_Alerts_Group_Id;
feedItem.Body = changedOpptyList;
INSERT feedItem;
}
}
I've never written an Apex Class before, so this part is new to me... Here's what I've done so far and it keeps failing!! I am open to starting over if I need to because I can't figure out how to fix it. I think it's probably going wrong at the boolean, but I really don't know.
@isTest
public class trgr_CreateChatterGroupAlerts_Test{
static Opportunity tOppty;
static CollaborationGroup chatterGrp;
public static void createTestData(){
tOppty = new Opportunity(
Name = 'Test Oppty',
Proposal__c = 'DMO003',
StageName = 'Ballpark',
CloseDate = System.today() + 10
);
INSERT tOppty;
chatterGrp = new CollaborationGroup(
Name = 'Test Group',
CollaborationType = 'Public'
);
INSERT chatterGrp;
}
public static void updateOpptyStage(){
tOppty.StageName = 'Proposal';
UPDATE tOppty;
}
public static Boolean isFeedItemCreated(){
FeedItem feedItem =
[
SELECT
Id,
ParentId,
Body
FROM
FeedItem
WHERE
ParentId = :chatterGrp.Id
ORDER BY CreatedDate DESC
LIMIT 1
];
if(feedItem!=NULL && feedItem.Body.contains(tOppty.Name)){
return TRUE;
}
else{
return FALSE;
}
}
public testMethod static void triggerInAction(){
test.startTest();
createTestData();
updateOpptyStage();
System.assert(true, isFeedItemCreated());
test.stopTest();
}
}
This is the error message I get when I run it:
Class: trgr_CreateChatterGroupAlerts3_Test
Method Name: triggerInAction
Pass/Fail: Fail
Error Message: System.QueryException: List has no rows for assignment to SObject
Stack Trace: Class.trgr_CreateChatterGroupAlerts3_Test.isFeedItemCreated: line 30, column 1
Class.trgr_CreateChatterGroupAlerts3_Test.triggerInAction: line 63, column 1
Thanks in advance for any help!!!
Here's my Apex Trigger. I have it in my sandbox and it does work! Everytime an opportunity's status changes, a post is made in a group chatter.
trigger trgr_CreateChatterGroupAlerts on Opportunity (after Update) {
List<Opportunity> updatedOpptyList =
[
SELECT
Id,
Name,
Account.Name,
StageName,
LastModifiedBy.Name
FROM
Opportunity
WHERE
Id IN :trigger.newMap.keyset()
];
String changedOpptyList = '';
for(Opportunity oppty : updatedOpptyList){
if(oppty.StageName != trigger.oldMap.get(oppty.Id).StageName){
changedOpptyList +=
'Opportunity ' + oppty.Name + ' (' + oppty.Account.Name + ')'+
' has its Stage changed from ' + trigger.oldMap.get(oppty.Id).StageName + ' to ' +
oppty.StageName + '\r\n';
}
}
if(changedOpptyList!=''){
FeedItem feedItem = new FeedItem();
feedItem.ParentId = System.Label.Opportunity_Alerts_Group_Id;
feedItem.Body = changedOpptyList;
INSERT feedItem;
}
}
I've never written an Apex Class before, so this part is new to me... Here's what I've done so far and it keeps failing!! I am open to starting over if I need to because I can't figure out how to fix it. I think it's probably going wrong at the boolean, but I really don't know.
@isTest
public class trgr_CreateChatterGroupAlerts_Test{
static Opportunity tOppty;
static CollaborationGroup chatterGrp;
public static void createTestData(){
tOppty = new Opportunity(
Name = 'Test Oppty',
Proposal__c = 'DMO003',
StageName = 'Ballpark',
CloseDate = System.today() + 10
);
INSERT tOppty;
chatterGrp = new CollaborationGroup(
Name = 'Test Group',
CollaborationType = 'Public'
);
INSERT chatterGrp;
}
public static void updateOpptyStage(){
tOppty.StageName = 'Proposal';
UPDATE tOppty;
}
public static Boolean isFeedItemCreated(){
FeedItem feedItem =
[
SELECT
Id,
ParentId,
Body
FROM
FeedItem
WHERE
ParentId = :chatterGrp.Id
ORDER BY CreatedDate DESC
LIMIT 1
];
if(feedItem!=NULL && feedItem.Body.contains(tOppty.Name)){
return TRUE;
}
else{
return FALSE;
}
}
public testMethod static void triggerInAction(){
test.startTest();
createTestData();
updateOpptyStage();
System.assert(true, isFeedItemCreated());
test.stopTest();
}
}
This is the error message I get when I run it:
Class: trgr_CreateChatterGroupAlerts3_Test
Method Name: triggerInAction
Pass/Fail: Fail
Error Message: System.QueryException: List has no rows for assignment to SObject
Stack Trace: Class.trgr_CreateChatterGroupAlerts3_Test.isFeedItemCreated: line 30, column 1
Class.trgr_CreateChatterGroupAlerts3_Test.triggerInAction: line 63, column 1
Thanks in advance for any help!!!
Hi Jewelyn,
Your code looks good, only thing which is concerned here is ChatterGroupName.
In Opportunity code, when StageName got updated. The ParentId of FeedItem is "Opportunity_Alerts_Group_Id".
While in test you are trying query FeedItems whose ParentId is in ChatterCollaborationGroup "Name = 'Test Group'".
Here, it may be a problem. As Opportunity_Alerts_Group_Id may have different ID (Salesforce standard ID), while creating a new chatterCollaborationGroup we will differnt ID (salesforce standard ID).
Hence there are no matching record and the error occurs.
Please try below test class code for FeedItem:
public static Boolean isFeedItemCreated(){
FeedItem feedItem =
[
SELECT
Id,
ParentId,
Body
FROM
FeedItem
WHERE
ParentId = :System.Label.Opportunity_Alerts_Group_Id;
ORDER BY CreatedDate DESC
LIMIT 1
];
if(feedItem!=NULL && feedItem.Body.contains(tOppty.Name)){
return TRUE;
}
else{
return FALSE;
}
}
Hope this will work for you.
Thanks,
Gaurav
Email: gauravgarg.nmims@gmail.com
All Answers
Hi Jewelyn,
Your code looks good, only thing which is concerned here is ChatterGroupName.
In Opportunity code, when StageName got updated. The ParentId of FeedItem is "Opportunity_Alerts_Group_Id".
While in test you are trying query FeedItems whose ParentId is in ChatterCollaborationGroup "Name = 'Test Group'".
Here, it may be a problem. As Opportunity_Alerts_Group_Id may have different ID (Salesforce standard ID), while creating a new chatterCollaborationGroup we will differnt ID (salesforce standard ID).
Hence there are no matching record and the error occurs.
Please try below test class code for FeedItem:
public static Boolean isFeedItemCreated(){
FeedItem feedItem =
[
SELECT
Id,
ParentId,
Body
FROM
FeedItem
WHERE
ParentId = :System.Label.Opportunity_Alerts_Group_Id;
ORDER BY CreatedDate DESC
LIMIT 1
];
if(feedItem!=NULL && feedItem.Body.contains(tOppty.Name)){
return TRUE;
}
else{
return FALSE;
}
}
Hope this will work for you.
Thanks,
Gaurav
Email: gauravgarg.nmims@gmail.com
You're storing the Chatter Group Id in a Custom Label. However, I would change it to either a custom setting or custom metadata. With a custom setting, you can actually insert values in your test class, which you will need as Gaurav alluded to.
Once you update the label to a custom setting, you can refactor your trigger like so:
Next, you would update your unit test to create the custom setting and add the chatter group that you create in your data setup method.
FYI, I also moved System.assert below Test.stopTest, just to make sure that all transactions have been completed prior to asserting the chatter group is created.
Also, to play admin / devil's advocate here, any particular reason you aren't looking at a Process to do this? A process can run on record update and has the ability to do Chatter posts too, even to a Group. If you're writing this trigger as a development excercise, that's fine, but this is a easy peasy Process to implement.
Thanks. Happy to help you.
Thanks,
Gaurav
Email: gauravgarg.nmims@gmail.com