1

I have a process that I have been building for the last couple weeks that should only be run in Sandbox. I have gotten most of test coverage finished and reporting 100% coverage in Sandbox UnitTests

TL;DR

I want to throw custom exceptions that are not caught in order to halt a the execution from running at all. However, I'm not sure how get customExceptions that halt execution to pass a deployment to production. How do write a test class for the following boiler plate code.

if(x == true){
throw customException('You can\'t do this. All executions stopped'); 

}

Problem

I have a class that runs a method doWork(). There is block of initialization code that checks the environment and then throws a customException. The behavior I would like is fullstop on execution if the conditions aren't met.

Here is the behavior I want if a dev accidentally runs this in Prod. enter image description here

Below is the the code for getting the result displayed in the screenshot. However, when trying to get this to pass TestMethods in Production, it fails.

Code with CustomException Option 1

  @TestVisible static Boolean s_isSandbox = false; 
    static {
        s_isSandbox = [SELECT Id, IsSandbox FROM Organization].isSandbox; 
    }
 public Boolean isSandbox(){
if (s_isSandbox == true) {
            throw new CustomDeveloperException('You cannot use this method in production');

        } else if (s_isSandbox == true || Test.isRunningTest()) {
            System.debug('Sandbox: Safe to run Queable Chain'); 
        } 
}

Code with CustomException Option 2

With this option, it defeats the purpose of my custom exception. My goal in throwing this is to halt execution and not allowing an processing to move further.

 @TestVisible static Boolean s_isSandbox = false; 
    static {
        s_isSandbox = [SELECT Id, IsSandbox FROM Organization].isSandbox; 
    }

 public Boolean isSandbox(){

 try {
            if (s_isSandbox == true && !Test.isRunningTest()) {
                throw new CustomDeveloperException('You cannot use this method in production');
    
            } else if (s_isSandbox == true || Test.isRunningTest()) {
                System.debug('Sandbox: Safe to run Queable Chain'); 
            } 
        } catch (Exception e) {
            System.debug(e.getMessage()); 
        }

        return s_isSandbox;  
    }

I have had a lot of help from the community on this subject. Thank you to everyone who has been responding. Very much appreciated, and looking forward to seeing what else I learn on this post.

My Test Classes Prior to Change

public static void testIsSandboxUtility(){
        SandboxRefreshUtility.s_isSandbox = true; 
        SandboxRefreshUtility util = new SandboxRefreshUtility(); 
        Boolean box = util.isSandbox(); 
        System.assertEquals(true, box, 'IsSandbox delivered false --> should be true'); 
    }
 @isTest
    public static void testIsNotSandboxUtility(){
        SandboxRefreshUtility.s_isSandbox = false;  
        Boolean box;
        SandboxRefreshUtility util = new SandboxRefreshUtility(); 
        try {
            box = util.isSandbox();    
        } catch (Exception e) {
            System.debug(e.getMessage());
            System.assertEquals('You cannot use this method in production', e.getMessage());
            System.assertEquals(null, box); 
        }
    }

3

If the purpose is to avoid executing in production, you can write:

@TestVisible static Boolean s_isSandbox = [SELECT Id, IsSandbox FROM Organization].isSandbox; 

 public Boolean isSandbox(){
    if(!s_isSandbox) {
        throw new CustomDeveloperException('You cannot use this method in production');
    }
 }
 

To get this to pass unit tests, you can write:

@isTest static void unitTest() {
  UtilClass.s_isSandbox = true;
  UtilClass.isSandbox();
}

The generality of the unitTest() is to imply that you will have to override any subsequent method that should only be run in a Sandbox Environment. The static variable will first be set to false in production, and then you override this with true for the test. No need to use Test.isRunningTest() here, and the variable is only accessible outside the class during a unit test (via @TestVisible).

Note that this is only a normal exception; it can still be caught. If you want to hard-stop, do not pass go, use an assertion instead:

@TestVisible static Boolean s_isSandbox = [SELECT Id, IsSandbox FROM Organization].isSandbox; 

 public Boolean isSandbox(){
   System.assert(s_isSandbox, 'You cannot use this method in production');
 }

Assertions will always halt execution dead in its tracks, with no possibility of handling, when they fail.

3
  • I believe that I have this set up in my test class. Going to modify what you have here and see if it works. The issue is that the Unit Test in Prod is hitting the exception.
    – thinker
    Jul 8 at 15:36
  • Got it. One thing that I had to realize was that the override had to be used in every subsequent method that should have only been called from a Sandbox.
    – thinker
    Jul 8 at 16:39
  • 1
    @thinker Yeah, that's unfortunate, but how it has to be.
    – sfdcfox
    Jul 8 at 16:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.