+ Start a Discussion
Amrita Priyadarshini Panda 2Amrita Priyadarshini Panda 2 

How to write a apex test class for the below apex class with maximum code coverage?

Apex class :-

    global class BlockIEPolicyCondition implements TxnSecurity.PolicyCondition {
     public boolean evaluate(TxnSecurity.Event e) {
      List<User> users = [SELECT ProfileId FROM User WHERE Id = :e.UserId];
            String profileId = (String)users.get(0).get('ProfileId');
            List<Profile> profiles = [SELECT Name FROM Profile WHERE Id = :profileId];
            String profileName = (String)profiles.get(0).get('Name');
            LoginHistory eObj = [SELECT Browser FROM LoginHistory WHERE Id = :e.data.get('LoginHistoryId')];
            string profileName1 = '"' +profileName + '"';
            String P=system.label.BlockIEPolicyProfile;
    Boolean ismatch = p.contains(profileName1);
      if(eObj.Browser == 'IE 11' || eObj.Browser == 'IE 10' || eObj.Browser == 'IE 9' || eObj.Browser == 'IE 8') {
       return true;
     return false; 
NagendraNagendra (Salesforce Developers) 
Hi Amrita,

Your specific case (finally):

Code that relies on standard Salesforce history objects are hard to test, because we don't have the ability to insert history records explicitly, and inserting/updating normal records (like an Account) does not cause a history record to be generated when executing a unit test.

In "Is it possible to test apex that relies on field history tracking?", I explain that you can use Test.loadData() to create otherwise uncreate-able data. The big caveat is that if you try to query the resulting records, you may not get back some (or any) of the data.

To gain the coverage you're looking for, you'll need to call your class's execute(TxnSecurity.Event)method, and you'll need to set the loginHistoryId of TxnSecurity.Event.data.

I think the general flow of your test will look something like
  • Call Test.loadData(), store the result in a list/map
  • Instantiate a TxnSecurity.Event object
  • e.data.put('loginHistoryId',`)
  • Create an instance of the class you're trying to test
  • Call the execute() method, and pass in your object from step 2
  • Assert that the response is true/false (depending on which one of your, at least 2, test methods you are in)
You'll need to experiment with whether the queried results from what you inserted via Test.loadData() actually contains the field(s) you need. If that doesn't work, then I'd try writing some test-specific code to inject the data you need, something like...
global class BlockIEPolicyCondition implements TxnSecurity.PolicyCondition {
    // The private modifier means that nothing else outside of this class can
    //   see/modify/use the variable
    // The @testVisible annotation makes an exception to the above, allowing
    //   a test class to get/set the value
    private LoginHistory testHistory;

    public boolean evaluate(TxnSecurity.Event e) {
        //<existing code unchanged and omitted>

        // We still want to run this query so we get coverage
        LoginHistory eObj = [SELECT Browser FROM LoginHistory WHERE Id = :e.data.get('LoginHistoryId')];

        // ...but in a test, we want to use our specific record
            eObj = this.testHistory;

        //<remaining code is unchanged, and omitted>
Hope this helps.