Why does Database class not provide commit method so that we can commit explicitly as well while in a transaction as we can do a rollback.
[SalesForce] Database class commit
Related Solutions
A quick search may have found the answer, but it is really simple:
Wrap the mock in a test.startTest();
test.startTest();
Test.setMock(HttpCalloutMock.class, new CalloutMock());
update opp; // this update makes callout
test.stoptest();
the reason is just like in a non-test environment. You cannot make a callout after doing any dml. Since you are creating a User, you cannot do a callout after in the same transaction. the test.StartTest() provides a new context for the callout to be run in as well as a new set of governor limits....
NOTE
Not sure why you have a batch code there, but if you are executing a batch from a trigger (potentially a problem) you will have to:
Call the start, execute, finish methods separately as it is a know issues that you will get this error regardless of the test.startTest if the callout is from a batch
If that is the case, unfortunatly you will have to wrap that part of your trigger that calls the batch in a :
if(!test.isRunningTest())
and change your test method to:
test.startTest();
Test.setMock(HttpCalloutMock.class, new CalloutMock());
update opp; // this update makes callout
//call your start method
[batch].execute(null,New sObject[]{opp});
//call your finish method
test.stoptest();
You can also just wrap the callout in the batch to prevent it from running during a test except when a static property is set. that way your trigger is unaltered and the batch / test controls when the callout is made during a test method
i.e in the batch.
public static testCallout = false;
.....
if( (testCallout && test.isRunningTest()) || !test.isRunningTest())
//make callout
then set the testCallout = true
from your test class
this leaves your trigger unaltered
You can find many topics on this issue by searching for "You have uncommitted work pending batch test" on this site
For the current code shown in the question the database.setsavepoint()
and database.rollback()
calls have no functional value and could be removed entirely for the same result. You aren't doing any DML operations, so there is nothing to rollback on.
If the code once called EventCreationhelper
there would have been some functional value to using the manual transaction statements. Most of what you need to know about using them is in Transaction Control. The following extract provides the best summary:
Sometimes during the processing of records, your business rules require that partial work (already executed DML statements) be “rolled back” so that the processing can continue in another direction. Apex gives you the ability to generate a savepoint, that is, a point in the request that specifies the state of the database at that time. Any DML statement that occurs after the savepoint can be discarded, and the database can be restored to the same condition it was in at the time you generated the savepoint.
Best Answer
We can't control commits, because there's too much system logic that depends on us not being able to commit directly to the database. For example, if we performed a commit and the transaction later failed, we would have committed data we can't roll back, but the remaining data hasn't been finalized, so we are left with a database in a possibly corrupt state; we then have to explicitly undo whatever we did up to the commit point.
Also, things like sending emails also commit records to the database. If we committed an email that contained some data, then the records themselves failed to save to the database, the email would be sent in error. There's simply too many complications with allowing users direct access to the database. This is why we have a database application layer exposed to us-- Salesforce abstracts the Oracle database away from us, so we can focus on business needs (CRM), rather than managing a database.
I could mention a ton of reasons why explicit commits would be a bad idea. It's hard enough to get commits "just right" when we're given our own databases (e.g. MySQL), without trying to predict how our commits might affect the underlying system logic. I do find myself wishing there was a way to side-commit records that should survive a failed transaction, but that's not a feature we have right now.