6

I've got a Trigger that will automatically add newly created Users to our companies main chatter group. It works as expected, but the test class is failing for some strange reason!

When I try to insert a new CollaborationGroup like below:

CollaborationGroup cg = new CollaborationGroup(
  Name = 'New Group',
  CollaborationType = 'Private'
);

INSERT cg;

... And query for that Id like below:

Id theChatterGroup = [SELECT Id FROM CollaborationGroup WHERE Name = 'New Group' LIMIT 1].Id;

I get the following error:

System.DmlException: Insert failed. First exception on row 0; first error: DUPLICATE_VALUE, An active or archived group with this name already exists or is being deleted. Choose a different name or try again in a few minutes.: [Name]

So I figured "okay, maybe CollaborationGroups are like profiles or something and don't need to be created in test classes?". But when I remove that insert, I get this error...

System.QueryException: List has no rows for assignment to SObject

... When I'm querying for the Id of the Chatter Group.

I feel like I'm missing something obvious here. Can anyone guide me in the right direction?

Edit The group exists in both production and I created it in the Sandbox. When we refreshed the sandbox, we didn't migrate and Chatter data.

Edit 2 I've tried checking if it exists, but still getting the same errors.

Integer cgExists = [SELECT Count() FROM CollaborationGroup WHERE Name = 'My Group'];

if (cgExists == 0) {
  CollaborationGroup cg = new CollaborationGroup(
    Name = 'My Group',
    CollaborationType = 'Private'
  );

  INSERT cg;
}
7
  • Are you sure your code that inserts the CollaborationGroup is not being called twice? Do you check that your query has results before inserting a new one?
    – Adrian Larson
    Jan 15, 2016 at 16:56
  • @AdrianLarson I've tried checking for this, but for some reason I'm still getting the same errors. Very odd.
    – Dan Jones
    Jan 15, 2016 at 17:04
  • Still having any issues with this one?
    – Adrian Larson
    Mar 7, 2016 at 15:08
  • @AdrianLarson Unfortunately yes. It was more of a "nice to have" thing which I've put on the backburner for now, but want to review it once I have more time. :)
    – Dan Jones
    Mar 8, 2016 at 10:10
  • One workaround would be to use a custom setting to store the CollaborationGroup Name. You would need to alter you trigger to look up the custom setting but this would allow you to set the custom setting in the test then create a group with the same name as what you just set the custom setting.
    – LMcDonald
    May 12, 2016 at 6:00

4 Answers 4

6

I ran into this same issue recently. In my case, I was trying to create multiple Chatter groups as a part of our Sandbox Refresh Script. Turns out existing CollaborationGroups are not visible during a test, but they are still evaluated for the unique group name requirement.

Using the @IsTest(SeeAllData=true) annotation for your test method will allow you to check if the group already exists; then you can either create a new group or interact with the existing group.

Class for creating Chatter groups

private static void createChatterGroups(List<String> grpNames){
    //Map existing Chatter groups that match list of group names
    Map<String, CollaborationGroup> grpMap = new Map<String, CollaborationGroup>();
    for (CollaborationGroup cg : [SELECT Name FROM CollaborationGroup WHERE Name IN :grpNames]) {
        grpMap.put(cg.Name, cg);
    }
    //Create Public Chatter groups
    List<CollaborationGroup> grps = new List<CollaborationGroup>();
    for (String grpName:grpNames) {
        //Confirm group does not already exist
        if (!grpMap.containsKey(grpName)) {
            CollaborationGroup g = new CollaborationGroup(Name=grpName, CollaborationType='Public');
            grps.add(g);
        }
    }
    insert grps;
}

Test class

@isTest(SeeAllData=true)
static void createChatterGroupTest() { 
    List<String> grpNames = new List<String> {'Group1','Group2'};

    Test.startTest();
    createChatterGroups(grpNames);
    Test.stopTest();

    //Validate that Chatter groups exist
    Map<String, CollaborationGroup> grpMap = new Map<String, CollaborationGroup>();
    for (CollaborationGroup cg : [SELECT Name FROM CollaborationGroup]) {
        grpMap.put(cg.Name, cg);
    }
    for (String grpName:grpNames) {
        system.assert(grpMap.containsKey(grpName), grpName + ' Chatter group was not created');
    }
}
1
  • This is the correct answer!!
    – hgolov
    Jan 15, 2019 at 9:12
3

You may want to adopt a loading strategy that will work even if called multiple times.

public static final String NEW_GROUP_NAME = 'New Group';
public static CollaborationGroup newGroupId
{
    get
    {
        if (newGroupId == null)
        {
            // first check if it's in the database
            List<CollaborationGroup> candidates = [
                SELECT Id FROM CollaborationGroup
                WHERE Name = :NEW_GROUP_NAME
            ];
            if (!candidates.isEmpty()) newGroupId = candidates[0].Id;
            else
            {
                // only create the group if it's missing
                CollaborationGroup newGroup = new CollaborationGroup(Name=NEW_GROUP_NAME);
                insert newGroup;
                newGroupId = newGroup.Id;
            }
        }
        return newGroupId;
    }
    private set;
}
4
  • I'll give this a go, thanks. Curious though, can public methods be accessed by @isTest static void abc123 methods? How would I get that data in to the isTest method or would the isTest method know it's already there?
    – Dan Jones
    Jan 15, 2016 at 17:07
  • Public methods can be accessed anywhere in your org, especially within a testmethod. The @TestVisible annotation just makes private methods more accessible.
    – Adrian Larson
    Jan 18, 2016 at 16:34
  • Thanks for the info. I did as you recommended, but to no avail. If I delete the Org in question, the test passes. But if that Org exists, it fails with the same error. Stuck for ideas on this one.
    – Dan Jones
    Jan 18, 2016 at 17:19
  • Were you ever able to solve this? I have the same use case and am stuck. May 8, 2017 at 19:48
2

I also ran into this. I eventually gave up on trying to make CG visible to both production and test.

Instead I created a test version of the collaboration group and put all my newly created test users in the test group. You can check Test.isRunningTest() to set the group's name to either the production or test version.

This also has the benefit of not depending on the state of any row in CollaborationGroup (seeAllData=false is the best way to write test classes in my view anyway).


Update -

We have a CollaborationGroup which contains all users of a specific application, named something like "All App Users".

In production Code (triggers, etc.) we use logic like this:

string nm = Test.isRunningTest() ? 'test All App Users' : 'All App Users'; CollaborationGroup cg = [SELECT Id FROM CollaborationGroup WHERE Name=:nm];

Any test classes refer only to "Test All App Users", which means the test Collaboration Group has to be created before each such test, and any users you'll be testing with need to be added to CollaborationGroupMember.

I think I read somewhere that SF purchased CollaborationGroup, ContentDocument and other chatter features from another company and they haven't integrated them so that they are consistent with the same way as other SF objects work. CollaborationGroup's behavior (is it a setup object or not?) is a good example of this issue. Another example is how ContentDocumentLink works. You can only query one document at a time (not a collection of docs).

1
  • Could you elaborate on this a little? Do you have any example of how to use this?
    – Dan Jones
    Jan 18, 2016 at 9:44
0

I was struggling with this issue until I realized I was calling the @testSetup method twice, I forgot the method runs automatically when the tests start so I called it inside my tests.

Hope this helps.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .