Como evitar o erro MIXED_DML_OPERATION em testes do Salesforce que criam usuários
-
24-09-2019 - |
Pergunta
Às vezes, nos testes do Salesforce, você precisa criar objetos Usuário para executar parte do teste como um tipo específico de usuário.
No entanto, desde a atualização do Salesforce Summer 08, as tentativas de criar objetos de usuário e objetos normais (como contas) no mesmo teste levam ao seguinte erro:
MIXED_DML_OPERATION, a operação DML no objeto de configuração não é permitida após você ter atualizado um objeto não configurado (ou vice-versa):Usuário, objeto original:Conta
Observe que o erro não ocorre quando você executa os testes no IDE Eclipse/Force.com, mas acontece quando você implanta no Salesforce e, em seguida, executa os testes no Salesforce.
Como reescrevo meus testes para evitar esse erro?
Aqui está um exemplo simples de um teste que causa o erro:
static testMethod void test_mixed_dmlbug() {
Profile p = [select id from profile where name='(some profile)'];
UserRole r = [Select id from userrole where name='(some role)'];
User u = new User(alias = 'standt', email='standarduser@testorg.com',
emailencodingkey='UTF-8', lastname='Testing',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='standarduser@testorg.com');
Account a = new Account(Firstname='Terry', Lastname='Testperson');
insert a;
System.runAs(u) {
a.PersonEmail = 'test@madeupaddress.com';
update a;
}
}
Solução
Ainda não há muitas pessoas do Salesforce aqui, eu acho.
Encontrei uma solução, não sei por que funciona, mas funciona.
Todas as partes do teste que acessam objetos normais precisam ser embrulhados em um sistema.RUNAS que usa explicitamente o usuário atual, como este:
User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
System.runAs ( thisUser ) {
// put test setup code in here
}
Portanto, o exemplo text_mixed_dmlbug dado na pergunta se tornaria:
static testMethod void test_mixed_dmlbug() {
User u;
Account a;
User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
System.runAs ( thisUser ) {
Profile p = [select id from profile where name='(some profile)'];
UserRole r = [Select id from userrole where name='(some role)'];
u = new User(alias = 'standt', email='standarduser@testorg.com',
emailencodingkey='UTF-8', lastname='Testing',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='standarduser@testorg.com');
a = new Account(Firstname='Terry', Lastname='Testperson');
insert a;
}
System.runAs(u) {
a.PersonEmail = 'test@madeupaddress.com';
update a;
}
}
Em seguida, os erros de Mixed_DML_operation param de acontecer.
Outras dicas
Parece que você encontrou uma solução alternativa.Eu só queria tentar esclarecer por que você recebeu esse erro.
Acho que você está enfrentando esse problema (por http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_dml_non_mix_sobjects.htm):
sObjects que não podem ser usados juntos em operações DML
Alguns sObjects exigem que você execute operações DML em apenas um tipo por transação.Por exemplo, você não pode inserir uma conta e depois inserir um usuário ou membro de um grupo em uma única transação.Os seguintes sObjects não podem ser usados juntos em uma transação:
* Group1 * GroupMember * QueueSObject * User2 * UserRole * UserTerritory * Territory
Importante A principal exceção a isso é quando você está usando o método Runas em um teste.
Além disso, o Notas de lançamento do verão 08 (esse link é um PDF) diga:
Em versões anteriores, em uma única transação que envolveu gatilhos, você pode executar operações de DML em mais de um tipo de objeto, por exemplo, você pode inserir uma conta e inserir um usuário.A partir do verão '08, você só pode executar operações DML em um único tipo de objeto da lista a seguir de Sobjects.
Por exemplo, você não pode inserir uma conta, inserir um usuário ou atualizar um grupo e inserir um membro do grupo.
- Grupo
- Membro do grupo
- QueueSObject
- Do utilizador
- Papel do usuário
- Território do usuário
- Território
Além disso, o usuário e o território agora suportam a inserção e atualizam as operações DML, e o Userrole agora suporta a inserção, atualiza as operações de exclusão e upsert DML.
As operações do APEX DML não são suportadas nos seguintes Sobjects:
- Regra de atribuição de território de conta
- AccountTerritoryAssignmentRuleItem
- Membro da equipe da conta do usuário
Esse comportamento está realmente documentado na documentação do Salesforce: http://www.salesforce.com/us/developer/docs/apexcode/index_left.htm#starttopic=content/apex_dml_non_mix_sobjects.htm?searchtype. Leia onde diz "IMPORTANTE A PRIMEIRA EXCEÇÃO A isto é quando você está usando o método Runas em um teste"
Acabei de encontrar isso na documentação:
Outros usos de
runAs
Você também pode usar o
runAs
método para executar operações DML mistas em seu teste, colocando as operações DML dentro dorunAs
bloquear.Dessa forma, você ignora o erro DML misto que seria retornado ao inserir ou atualizar objetos de configuração junto com outros objetos.sObjects
.VersObjects
Isso não pode ser usado em conjunto em operações DML.
Então parece que RunAs
solução alternativa não é uma solução alternativa, mas é assumida pela Salesforce como a única maneira de resolver o problema misto de DML.
Espero que isto ajude
Esse erro é tão comum ao tentar criar registros de usuário e outros objetos em uma única transação no Apex.
Solução alternativa na classe/gatilho Apex: use o método futuro para criar usuário quando encontrado o erro
Solução alternativa na classe de teste: não tente criar um novo dados do usuário, use))>
Snippet de código em -https://thesalesforcecev.blogspot.com/2019/07/mixeddmloperation-dml-operation-on.html