0

I'm working in an old Salesforce.

In accounts, they have a lot of records, and a validation rule that verifies if a check box is selected and a lookup is null.

The rule was created on 2015/01/01.

The problem is that when i tried to update some accounts there are some of them created before 2015/01/01 that do not satisfy the validation rule.

I created a batch to deselect the check box of the accounts with this issue.

The batch works without problem, but the unit-test for the batch don't allow me to insert an account with the check box selected and a lookup at null.

My solution was insert a record with the check box deselect in test class, and adding if(Test.isRunningTest()) to the start method of the batch with another query to reach the execute method.

My question is, can I deactivate a validation rule for a test method and how? and, if I can not deactivate a validation rule, are there a better solution for this problem?

EDITED: We can not create, edit, delete or deactivate any validation rule, or edit the object in production.

1

For your specific situation, you might insert a record where the lookup is not null, then delete the record that was used in the lookup (unless you've also prevented that loophole). In the more general case, you shouldn't be trying to circumvent validation rules. As an alternative to Test.isRunningTest(), you can also use the tried and true query override method.

public class SomeBatch implements Database.Batchable<SObject> {
  @TestVisible String query = 'Your query here';
  public Database.QueryLocator start(Database.BatchableContext context) {
    return Database.getQueryLocator(query);
  }
  ...
}

Then, you can inject the query of your choosing:

// Setup test data
SomeBatch b = new SomeBatch();
b.query = 'your test query here';
Test.startTest();
Database.executeBatch(b);
Test.stopTest();
// Verify output

Edit: We can't serialize a QueryLocator (see prior version), so we need a String instead. Still, it leaves us with the ability to inject without mixing our test code in with the real code.

  • Thanks.I did not realize that I can add an object to the look up and delete it after. I will use the second option, editing the query in the test class because I have an other development that interfires in the deletion of the object. – Pestana May 28 '18 at 11:57
3

I don't agree with the other answers here. You should not need to muck with your validation rule or data model to perform a test of your batch class. Instead, you can use an inversion of control pattern.

Here's a very simple example.

public void doStuff() {
    List<myobject__c> myList = [SELECT fields FROM myobject__c ...];

    for (myobject__c m : myList) {
        // Do work
    }

    update myList;
}

Because this method directly accesses the database before taking action, your test class's only means of controlling its behavior is inserting data for it to see. If you can't insert that data, you have a problem.

A very simple species of inversion of control here might simply break out the work method:

public void doStuff() {
    List<myobject__c> myList = [SELECT fields FROM myobject__c ...];
    doWork(myList);
    update myList;
}

 public void doWork(List<myobject__c> myList) {

    for (myobject__c m : myList) {
        // Do work
    }
}

Now our test method can directly call doWork() with a constructed list (maybe even a list of objects that exist only in memory, and haven't been inserted into the database) and directly inspect the results before DML is performed.

You could potentially use a pattern like this to test your code against records you cannot actually insert.

More advanced inversion of control can use a delegate object passed in to the class under test to implement all of its external connections, like database access. The test class injects a delegate that returns predictable test values to the code being tested, and then evaluates the results.

  • If the test method omits the DML statement and only calls doWork() how do we ensure the code will work for users when a validation rule or an automation process is added or modified? I believe Apex tests need to fail to trigger a build failure and block off deployment. – Mossi Feb 28 at 20:32
  • @Mossi It won't. I wouldn't use this specific strategy in a situation where the existing org wasn't somehow broken. – David Reed Feb 28 at 22:47
0

Our solution for testing things without validation rule was:

Adding checkbox field on user object called something like "omitValidations" and then add checking it in all validation rules using $User.omitValidations__c == false && rules

Then in test you can create user with that field set to true and use System.runAs

  • Thanks, but we can not create, edit, delete or deactivate any validation rule, or edit the object in production. And upload the test class to production will crash. – Pestana May 25 '18 at 11:48
0

You cannot deactivate a validation rule for test classes.

Instead, you can have a checkbox field in your object that is unchecked by default.

Modify your validation rule, so that it fires only if the checkbox field is unchecked.

And in test class, create the test data with that checkbox field checked.

Hope this helps.

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.