Loading
Einrichtung und Pflege der Salesforce-Organisation
Inhalt
Filter auswählen

          Keine Ergebnisse
          Keine Ergebnisse
          Hier sind einige Suchtipps

          Überprüfen Sie die Schreibweise Ihrer Stichwörter.
          Verwenden Sie allgemeinere Suchbegriffe.
          Wählen Sie weniger Filter aus, um Ihre Suche auszuweiten.

          Gesamte Salesforce-Hilfe durchsuchen
          Verbesserte Apex-Transaktionssicherheitstests

          Verbesserte Apex-Transaktionssicherheitstests

          Das Schreiben zuverlässiger Tests ist eine bewährte Vorgehensweise, um sicherzustellen, dass sich Ihr Code erwartungsgemäß verhält, und um Fehler zu finden, bevor Ihre Benutzer und Kunden es tun. Es ist sogar noch wichtiger, Tests für den Apex-Code Ihrer Transaktionssicherheitsrichtlinie zu schreiben, da er bei wichtigen Benutzeraktionen in Ihrer Salesforce-Organisation ausgeführt wird. Beispielsweise kann ein Fehler in Ihrer LoginEvent-Richtlinie, der während des Tests nicht erkannt wird, dazu führen, dass Ihre Benutzer aus Ihrer Organisation ausgesperrt werden, was natürlich vermieden werden sollte.

          Erforderliche Editionen

          Verfügbar in Salesforce Classic (nicht in allen Organisationen verfügbar) und Lightning Experience.

          Verfügbarkeit: Enterprise, Unlimited und Developer Edition

          Hierfür sind Add-On-Abonnements für Salesforce Shield oder die Salesforce-Ereignisüberwachung erforderlich.

          ACHTUNG
          ACHTUNG Verwenden Sie API-Version 47.0 oder höher beim Schreiben von Apex-Tests für erweiterte Transaktionssicherheitsrichtlinien.

          Wenn Sie Ihren Apex-Code testen, indem Sie eine Reihe von Bedingungen simulieren, schreiben Sie definitionsgemäß Einheitentests. Das Schreiben von Einheitentests ist jedoch nicht genug. Arbeiten Sie mit Ihren Geschäfts- und Sicherheitsteams zusammen, um alle Ihre Anwendungsfälle zu verstehen. Erstellen Sie anschließend mithilfe von Testdaten in einer Sandbox-Umgebung einen umfassenden Testplan, der die Erfahrung Ihrer tatsächlichen Benutzer nachahmt. Der Testplan beinhaltet in der Regel sowohl manuelle Tests als auch automatisierte Tests mithilfe externer Tools wie Selenium.

          Im Folgenden finden Sie für den Einstieg einige Beispiele für Einheitentests. Hier finden Sie die Apex-Richtlinie, die getestet werden soll.

          global class LeadExportEventCondition implements TxnSecurity.EventCondition {
              public boolean evaluate(SObject event) {
                  switch on event{
                      when ApiEvent apiEvent {
                          return evaluate(apiEvent.QueriedEntities, apiEvent.RowsProcessed);
                      }
                      when ReportEvent reportEvent {
                          return evaluate(reportEvent.QueriedEntities, reportEvent.RowsProcessed);
                      }
                      when ListViewEvent listViewEvent {
                          return evaluate(listViewEvent.QueriedEntities, listViewEvent.RowsProcessed);
                      }
                      when null {
                           return false;   
                      }
                      when else {
                          return false;
                      }
                  }
              }
          
              private boolean evaluate(String queriedEntities, Decimal rowsProcessed){
                  if (queriedEntities.contains('Lead') && rowsProcessed > 2000){
                      return true;
                  }
                  return false;
              }
          }

          Planen und Schreiben von Tests

          Bevor mit dem Schreiben der Tests begonnen wird, sollten die positiven und negativen Anwendungsfälle hervorgehoben werden, die von unserem Testplan abgedeckt werden.

          Positive Testfälle
          Empfängt die Methode evaluate Folgendes … Und … Dann gibt die Methode evaluate Folgendes zurück …
          Ein "ApiEvent"-Objekt Das Objekt "ApiEvent" verfügt über "Lead" im zugehörigen Feld "QueriedEntities" und im Feld "RowsProcessed" über eine Zahl, die größer als 2000 ist. true
          Ein "ReportEvent"-Objekt Das Objekt "ReportEvent" verfügt über "Lead" im zugehörigen Feld "QueriedEntities" und im Feld "RowsProcessed" über eine Zahl, die größer als 2000 ist. true
          Ein ListViewEvent-Objekt Das Objekt "ListViewEvent" verfügt über "Lead" im zugehörigen Feld "QueriedEntities" und im Feld "RowsProcessed" über eine Zahl, die größer als 2000 ist. true
          Ein beliebiges Ereignisobjekt Das Ereignis verfügt nicht über "Lead" im zugehörigen Feld "QueriedEntities" und verfügt im Feld "RowsProcessed" über eine Zahl, die größer als 2000 ist. false
          Ein beliebiges Ereignisobjekt Das Ereignis verfügt über "Lead" im zugehörigen Feld "QueriedEntities" und im Feld "RowsProcessed" über eine Zahl, die kleiner oder gleich 2000 ist. false
          Ein beliebiges Ereignisobjekt Das Ereignis verfügt nicht über "Lead" im zugehörigen Feld "QueriedEntities" und verfügt im Feld "RowsProcessed" über eine Zahl, die kleiner oder gleich 2000 ist. false
          Negative Testfälle
          Empfängt die Methode evaluate Folgendes … Und … Dann gibt die Methode evaluate Folgendes zurück …
          Ein LoginEvent-Objekt (ohne Bedingung) false
          Ein Nullwert (ohne Bedingung) false
          Ein "ApiEvent"-Objekt Das Feld QueriedEntities entspricht "null" false
          Ein "ReportEvent"-Objekt Das Feld RowsProcessed entspricht "null" false

          Im Folgenden finden Sie den Apex-Testcode, der alle diese Anwendungsfälle implementiert.

          /**
           * Tests for the LeadExportEventCondition class, to make sure that our Transaction Security Apex 
           * logic handles events and event field values as expected.
           **/
           @isTest
           public class LeadExportEventConditionTest {
           
              /**
               * ------------ POSITIVE TEST CASES ------------
               ** /
           
               /**
                * Positive test case 1: If an ApiEvent has Lead as a queried entity and more than 2000 rows 
                * processed, then the evaluate method of our policy's Apex should return true.
                **/ 
                static testMethod void testApiEventPositiveTestCase() {
                    // set up our event and its field values
                    ApiEvent testEvent = new ApiEvent();
                    testEvent.QueriedEntities = 'Account, Lead';
                    testEvent.RowsProcessed = 2001;
                    
                    // test that the Apex returns true for this event
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assert(eventCondition.evaluate(testEvent));   
                }
               
               /**
                * Positive test case 2: If a ReportEvent has Lead as a queried entity and more than 2000 rows 
                * processed, then the evaluate method of our policy's Apex should return true.
                **/ 
                static testMethod void testReportEventPositiveTestCase() {
                    // set up our event and its field values
                    ReportEvent testEvent = new ReportEvent();
                    testEvent.QueriedEntities = 'Account, Lead';
                    testEvent.RowsProcessed = 2001;
                    
                    // test that the Apex returns true for this event
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assert(eventCondition.evaluate(testEvent));   
                }
               
               /**
                * Positive test case 3: If a ListViewEvent has Lead as a queried entity and more than 2000 rows 
                * processed, then the evaluate method of our policy's Apex should return true.
                **/ 
                static testMethod void testListViewEventPositiveTestCase() {
                    // set up our event and its field values
                    ListViewEvent testEvent = new ListViewEvent();
                    testEvent.QueriedEntities = 'Account, Lead';
                    testEvent.RowsProcessed = 2001;
                    
                    // test that the Apex returns true for this event
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assert(eventCondition.evaluate(testEvent));   
                }
               
               /**
                * Positive test case 4: If an event does not have Lead as a queried entity and has more 
                * than 2000 rows processed, then the evaluate method of our policy's Apex 
                * should return false.
                **/ 
                static testMethod void testOtherQueriedEntityPositiveTestCase() {
                    // set up our event and its field values
                    ApiEvent testEvent = new ApiEvent();
                    testEvent.QueriedEntities = 'Account';
                    testEvent.RowsProcessed = 2001;
                    
                    // test that the Apex returns false for this event
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assertEquals(false, eventCondition.evaluate(testEvent));   
                }
                
              /**
                * Positive test case 5: If an event has Lead as a queried entity and does not have 
                * more than 2000 rows processed, then the evaluate method of our policy's Apex 
                * should return false.
                **/ 
                static testMethod void testFewerRowsProcessedPositiveTestCase() {
                    // set up our event and its field values
                    ReportEvent testEvent = new ReportEvent();
                    testEvent.QueriedEntities = 'Account, Lead';
                    testEvent.RowsProcessed = 2000;
                    
                    // test that the Apex returns false for this event
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assertEquals(false, eventCondition.evaluate(testEvent));   
                }
                
              /**
                * Positive test case 6: If an event does not have Lead as a queried entity and does not have 
                * more than 2000 rows processed, then the evaluate method of our policy's Apex 
                * should return false.
                **/ 
                static testMethod void testNoConditionsMetPositiveTestCase() {
                    // set up our event and its field values
                    ListViewEvent testEvent = new ListViewEvent();
                    testEvent.QueriedEntities = 'Account';
                    testEvent.RowsProcessed = 2000;
                    
                    // test that the Apex returns false for this event
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assertEquals(false, eventCondition.evaluate(testEvent));   
                }
                
                /**
                 * ------------ NEGATIVE TEST CASES ------------
                 **/
               
               /**
                * Negative test case 1: If an event is a type other than ApiEvent, ReportEvent, or ListViewEvent,
                * then the evaluate method of our policy's Apex should return false.
                **/
                static testMethod void testOtherEventObject() {
                    LoginEvent loginEvent = new LoginEvent();
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assertEquals(false, eventCondition.evaluate(loginEvent));   
                } 
           
               /**
                * Negative test case 2: If an event is null, then the evaluate method of our policy's
                * Apex should return false.
                **/
                static testMethod void testNullEventObject() {
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assertEquals(false, eventCondition.evaluate(null));   
                } 
               
               /**
                * Negative test case 3: If an event has a null QueriedEntities value, then the evaluate method 
                * of our policy's Apex should return false.
                **/
                static testMethod void testNullQueriedEntities() {
                    ApiEvent testEvent = new ApiEvent(); 
                    testEvent.QueriedEntities = null;
                    testEvent.RowsProcessed = 2001;
                    
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assertEquals(false, eventCondition.evaluate(testEvent));   
                }
               
               /**
                * Negative test case 4: If an event has a null RowsProcessed value, then the evaluate method 
                * of our policy's Apex should return false.
                **/
                static testMethod void testNullRowsProcessed() {
                    ReportEvent testEvent = new ReportEvent(); 
                    testEvent.QueriedEntities = 'Account, Lead';
                    testEvent.RowsProcessed = null;
                    
                    LeadExportEventCondition  eventCondition = new LeadExportEventCondition();
                    System.assertEquals(false, eventCondition.evaluate(testEvent));   
                } 
           }

          Eingrenzen des Richtliniencodes nach dem Ausführen der Tests

          Angenommen, Sie führen die Tests aus und der Testkundenvorgang "testNullQueriedEntities" schlägt mit der Fehler "System.NullPointerException: Attempt to de-reference a null object" fehl. Gute Neuigkeiten: Die Tests haben einen Bereich der Transaktionssicherheitsrichtlinie identifiziert, in dem keine Überprüfungen auf unerwartete oder Nullwerte vorgenommen werden. Da Richtlinien während wichtiger Organisationsvorgänge ausgeführt werden, sollten Sie sicherstellen, dass die Richtlinien kontrolliert fehlschlagen, falls ein Fehler vorliegt, damit sie keine wichtigen Funktionen blockieren.

          Im Folgenden erfahren Sie, wie Sie die Methode "evaluate" in der Apex-Klasse aktualisieren, um diese Nullwerte kontrolliert zu verarbeiten.

          private boolean evaluate(String queriedEntities, Decimal rowsProcessed) {
              boolean containsLead = queriedEntities != null ? queriedEntities.contains('Lead') : false;
              if (containsLead && rowsProcessed > 2000){
                  return true;
              }
              return false;
          }

          Der Code wurde geändert, sodass zunächst überprüft wird, ob der Wert null ist, bevor der Vorgang ".contains" in der Variablen "queriedEntities" durchgeführt wird. Durch diese Änderung wird sichergestellt, dass der Code den Verweis auf ein Nullobjekt nicht aufhebt.

          Wenn Sie im Allgemeinen unerwartete Werte oder Situationen in Ihrem Apex-Code ermitteln, haben Sie zwei Möglichkeiten. Ermitteln Sie, was für Ihre Benutzer am besten ist, wenn Sie festlegen, welche Option ausgewählt werden soll:

          • Ignorieren Sie die Werte oder Situation und geben Sie "false" zurück, damit die Richtlinie nicht ausgelöst wird.
          • Veranlassen Sie, dass der Vorgang fehlerhaft geschlossen wird, indem "true" zurückgegeben wird.

          Erweitertes Beispiel

          Im Folgenden finden Sie eine komplexere Apex-Richtlinie, die SOQL-Abfragen verwendet, um das Profil des Benutzers abzurufen, der versucht, sich anzumelden.

          global class ProfileIdentityEventCondition implements TxnSecurity.EventCondition {
          
              // For these powerful profiles, let's prompt users to complete 2FA
              private Set<String> PROFILES_TO_MONITOR = new Set<String> { 
                  'System Administrator', 
                  'Custom Admin Profile'
              };
              
              public boolean evaluate(SObject event) {
                  LoginEvent loginEvent = (LoginEvent) event;
                  String userId = loginEvent.UserId;
                  
                  // get the Profile name from the current users profileId
                  Profile profile = [SELECT Name FROM Profile WHERE Id IN 
                              (SELECT profileId FROM User WHERE Id = :userId)];
                  
                  // check if the name of the Profile is one of the ones we want to monitor
                  if (PROFILES_TO_MONITOR.contains(profile.Name)) {
                      return true;
                  }
                  
                  return false;
              }   
           }

          Im Folgenden ist unser Testplan für positive Testfälle beschrieben:

            • Wenn der Benutzer, der versucht, sich anzumelden, über das zu überwachende Profil verfügt, gibt die "evaluate"-Methode "true" zurück.
            • Wenn der Benutzer, der versucht, sich anzumelden, nicht über das zu überwachende Profil verfügt, gibt die "evaluate"-Methode "false" zurück.

          Und hier unser Plan für negative Testfälle:

            • Wenn die Abfrage nach dem Profilobjekt eine Ausnahme auslöst, gibt die "evaluate"-Methode "false" zurück.
            • Wenn die Abfrage nach dem Profilobjekt null zurückgibt, gibt die "evaluate"-Methode "false" zurück.

          Da jedem Salesforce-Benutzer immer ein Profil zugewiesen ist, müssen Sie dafür keinen negativen Test erstellen. Es ist zudem nicht möglich, tatsächliche Tests für die beiden negativen Testfälle zu erstellen. Wir erledigen diese Maßnahmen, indem wir die Richtlinie selbst aktualisieren. Die Anwendungsfälle in unserem Plan werden jedoch explizit aufgelistet, um sicherzustellen, dass viele verschiedene Situationen abgedeckt sind.

          Die positiven Testfälle basieren auf den Ergebnissen von SQQL-Abfragen. Um sicherzustellen, dass diese Abfragen richtig ausgeführt werden, müssen zudem einige Testdaten erstellt werden. Im Folgenden finden Sie Testcode.

          /**
           * Tests for the ProfileIdentityEventCondition class, to make sure that our 
           * Transaction Security Apex logic handles events and event field values as expected.
           **/
           @isTest
           public class ProfileIdentityEventConditionTest {
           
              /**
               * ------------ POSITIVE TEST CASES ------------
               ** /
           
               /**
                * Positive test case 1: Evaluate will return true when user has the "System 
                * Administrator" profile.
                **/ 
                static testMethod void testUserWithSysAdminProfile() {
                    // insert a User for our test which has the System Admin profile
                    Profile profile = [SELECT Id FROM Profile WHERE Name='System Administrator'];
                    assertOnProfile(profile.id, true); 
                }
          
               /**
                * Positive test case 2: Evaluate will return true when the user has the "Custom
                * Admin Profile"
                **/ 
                static testMethod void testUserWithCustomProfile() {
                    // insert a User for our test which has the System Admin profile
                    Profile profile = [SELECT Id FROM Profile WHERE Name='Custom Admin Profile'];
                    assertOnProfile(profile.id, true);
                }
                
               /**
                * Positive test case 3: Evalueate will return false when user doesn't have
                * a profile we're interested in. In this case we'll be using a profile called
                * 'Standard User'.
                **/ 
                static testMethod void testUserWithSomeProfile() {
                    // insert a User for our test which has the System Admin profile
                    Profile profile = [SELECT Id FROM Profile WHERE Name='Standard User'];
                    assertOnProfile(profile.id, false);
                }
                
                /**
                 * Helper to assert on different profiles.
                 **/
                static void assertOnProfile(String profileId, boolean expected){
                    User user = createUserWithProfile(profileId);
                    insert user;
                
                    // set up our event and its field values
                    LoginEvent testEvent = new LoginEvent();
                    testEvent.UserId = user.Id;
                    
                    // test that the Apex returns true for this event
                    ProfileIdentityEventCondition  eventCondition = new ProfileIdentityEventCondition();
                    System.assertEquals(expected, eventCondition.evaluate(testEvent));  
                }
                
                /**
                 * Helper to create a user with the given profileId.
                 **/
                static User createUserWithProfile(String profileId){
                    // Usernames have to be unique.
                    String username = 'ProfileIdentityEventCondition@Test.com';
                    
                    User user = new User(Alias = 'standt', Email='standarduser@testorg.com', 
                    EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US', 
                    LocaleSidKey='en_US', ProfileId = profileId, 
                    TimeZoneSidKey='America/Los_Angeles', UserName=username);
                    return user;
                }
           }

          Behandeln Sie die beiden negativen Testfälle, indem Sie den Transaktionssicherheitsrichtlinien-Code aktualisieren, um beim Abfragen des Profilobjekts eine Überprüfung auf Ausnahmen oder Nullergebnisse vorzunehmen.

          global class ProfileIdentityEventCondition implements TxnSecurity.EventCondition {
          
              // For these powerful profiles, let's prompt users to complete 2FA
              private Set<String> PROFILES_TO_MONITOR = new Set<String> { 
                  'System Administrator', 
                  'Custom Admin Profile'
              };
              
              public boolean evaluate(SObject event) {
                  try{
                      LoginEvent loginEvent = (LoginEvent) event;
                      String userId = loginEvent.UserId;
                      
                      // get the Profile name from the current users profileId
                      Profile profile = [SELECT Name FROM Profile WHERE Id IN 
                                  (SELECT profileId FROM User WHERE Id = :userId)];
                      
                      if (profile == null){
                          return false;
                      }
                      
                      // check if the name of the Profile is one of the ones we want to monitor
                      if (PROFILES_TO_MONITOR.contains(profile.Name)) {
                          return true;
                      }
                      return false;
                  } catch(Exception ex){
                      System.debug('Exception: ' + ex);
                      return false;   
                  }
              }   
           }
           
          Laden
          Salesforce Help | Article