Wrap all integration tests with transaction/rollback

I have been playing around with TestBox to try and come up with a way to wrap all integration tests with a transaction/rollback as opposed to having to implement it in each test suite. This is what I have come up with so far wanted to see if anyone has a different/better way?

In BaseIntegrationTest.cfc I define a wrapTransaction function that I can resuse to wrap test suites with a transaction/rollback block.

/**
 * Base Integration Test Object
 */
component extends="coldbox.system.testing.BaseTestCase" appMapping="/root" {

	this.loadColdBox = true;

	/**
	 * Executes before all tests have been run
	 */
	function beforeAll() {
		super.beforeAll();

		// setup the model
		super.setup();
	};

	/**
	 * Executes after all tests have been run
	 */
	function afterAll() {
		super.afterAll();
	};
	
	/**
	 * Wraps specs with transaction to rollcack database
	 */
	function wrapTransaction( spec, suite, data ){

		try {
			// Make sure we always rollback
			transaction {
				arguments.spec.body();
				transaction action="rollback";
			}
		}
		catch ( any e ) {
			transactionRollback();
			rethrow;
		}
	};

}

Here is an example integration test that inherits from the BaseIntegrationTest then calls aroundEach(wrapTransaction);

component extends="tests.specs.integration.BaseIntegrationTest" {
...
function run(){

		describe( "ToDo Handler", function(){

			aroundEach(wrapTransaction);

			beforeEach(function( currentSpec ){
				// Setup as a new ColdBox request, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST.
				setup();
			});

			it( "adds a new todo item", function(){
				var testValue = $mockData.words(2);
				getRequestContext().setValue( name="description", value=testValue);

				var event = execute( event="main.add", renderResults=true );
				var todoItems = event.getValue( name="todoItems", private=true );
				expect(	valueList( todoItems.description ) ).toInclude(testValue);
			});

Any ideas/feedback is appreciated.

You are in the right direction. There are many ways to skin the cat. Your approach is good! You can also use a @aroundEach annotation, which basically makes ANY method fire on aroundEach() for you. So you can tag any method to be executed for you.

We use something similar to you in our ContentBox tests:

More Exaxmples


/**
	 * Helper to execeute after each spec
	 *
	 * @afterEach
	 */
	function clearAfterEachSpec(){
		ormClearSession();
	}

	/**
	 * Helper to Wrap your code in a transaction block
	 */
	function inTransaction( target ){
		transaction action="begin" {
			try {
				return arguments.target();
			} catch ( any e ) {
				rethrow;
			} finally {
				transaction action="rollback";
				ormClearSession();
			}
		}
	}

1 Like

The annotation worked nicley. I missed that in the documentation. Thank you for the tip!