1

I'm trying to create a test class for this operation:

List<UserTeamMember> listUserTeamMember = [Select id, ownerId, TeamMemberRole, OpportunityAccessLevel, userId from UserTeamMember where OwnerId =: mapOutboundUserInboundUser.values()];

    mapIdOutboundUser = new Map<Id,User>([SELECT id, Network__c FROM User WHERE Id IN: mapOutboundUserInboundUser.values()]);

    for(UserTeamMember utm : listUserTeamMember){
        if(mapInboundUserAccTeam.get(utm.ownerId) == null){
            List<UserTeamMember> listatm = new List<UserTeamMember>();
            listatm.add(utm);
            mapInboundUserAccTeam.put(utm.ownerId, listatm);
        }else{
            mapInboundUserAccTeam.put(utm.ownerId, (List<UserTeamMember>) mapInboundUserAccTeam.get(utm.ownerId).add(utm));
        }
    }

Where mapOutboundUserInboundUser is just a map of outbound users that will be replaced with Inbound users. After that the map filled in the first code sample it is used like below.

if(mapInboundUserAccTeam.get(incomingUser) != null){
                for(UserTeamMember utm : mapInboundUserAccTeam.get(incomingUser)){
                    OpportunityTeamMember oppTM = new OpportunityTeamMember(OpportunityId = opp.Id, TeamMemberRole = utm.TeamMemberRole, OpportunityAccessLevel = utm.OpportunityAccessLevel, UserId = utm.userId);
                    listUserOppTeamMemberToadd.add(oppTM);
                }
            }

The aim of the process is to change ownership of an opportunity and Also change the opportunityTeamMembers associated with that opportunity depending on the UserTeamMember of the incoming users

In my test class i'm querying a user from the object UserTeamMember. My goal is to get a user that have UserTeamMember so I can test my class above. I do as follow:

Id idUserOppTest = [SELECT Id, OwnerId FROM UserTeamMember LIMIT 1].OwnerId;

It works nice when i'm on a test org, as we do have some Users with UserTeamMember.

My problem is that we do have a process where our code is deployed on a blank scratch org using a pipeline. When this test class is executed on that blank scratch the request above return no results. As this scratch has no user with UserTeamMember linked to it.

I did try inserting the UserTeamMember but it does not allow insert DML.

UserTeamMember Apex DML

How could I create a user with a UserTeamMember inside my test class? So it can be executed on any orgs?

Thanks in advance.

7
  • This is an X-Y Problem. What you should be asking about is how to fix your code, so that it does not have this dependency. The direct answer to this question is "use force:data:record:create to create the record you need," but that won't help you if you want to use Unlocked/Managed/2nd Gen Managed packages. You need code that stands alone without creating this record. The DML limitation only applies to Apex, and not to standard APIs.
    – sfdcfox
    Oct 24, 2022 at 13:43
  • First of all thanks for the answer. Just a genuine question here: I have a for loop of 10 lines that loops around users with UserTeamMember. If I want to test it how am I supposed to not have a dependency to creating a user with UserTeamMember? I don't understand Oct 24, 2022 at 13:52
  • I guess I edited the question to only ask one question and not 2. Oct 24, 2022 at 14:02
  • Yes, if I try to answer your question as written, it'll be long and generic. The most direct way to get a concise answer is to include the code you're trying to test, and whatever test logic you've written so far.
    – sfdcfox
    Oct 24, 2022 at 14:46
  • I'm sorry I didn't think it was revelant in the first place, but my bad. I edited my question again. Oct 24, 2022 at 14:59

1 Answer 1

3

For a scenario like this, you need to use a technique called dependency injection. There're a few ways to do this, but it'll require changing the live code a bit. The test itself can't create these records, so we need a way to fake it, and this is where dependency injection comes in.

First, in the live code, we'll set up an inner class to get our UserTeamMember records:

@TestVisible private virtual class UserTeamHelper {
  public virtual UserTeamMember[] getTeamMembers(Set<Id> userIds) {
    return [SELECT FIELDS(STANDARD) FROM UserTeamMember WHERE Id = :userIds];
  }
}
@TestVisible static UserTeamHelper helper = new UserTeamHelper();

Which your method will use:

UserTeamMember[] userTeamMembers = helper.getTeamMembers(mapOutboundUserInboundUser.values());

Now, in your unit test, you can override this behavior:

class UserTeamHelperMock extends ControllerClass.UserTeamHelper {
  public override UserTeamMember[] getTeamMembers(Set<Id> userIds) {
    UserTeamMember[] results = new UserTeamMember[0];
    for(Id userId: userIds) {
      results.add(new UserTeamMember(OwnerId=userId));
    }
    return results;
  }
}

Replace ControllerClass with the class that holds your method.

After this, our unit test is ready to be written:

// Or as many users as you need to make this work
Set<Id> userIds = new Set<Id>{ UserInfo.getUserId() };
ControllerClass.UserTeamHelper = new UserTeamHelperMock();
Test.startTest();
// If static:
ControllerClass.someMethod(userIds);
// If instance:
new ControllerClass.someMethod(userIds);

Note that we never perform any DML; we just create the records in memory, allowing our data to flow from the mock to the method. This is the essence of dependency injection.

You can also use the Stub API, but that may be overkill for your use case.

You must log in to answer this question.

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