I’ve run into what appears to be unexpected singleton state persistence when mocking with TestBox, and I want to sanity-check my understanding of how the ColdBox virtual app and WireBox singletons behave between tests and requests.
I always assumed that each request (and each test run) reset the ColdBox virtual app and WireBox singletons. However, I’m seeing mocked singleton methods persist across separate test CFCs, and even across subsequent requests, unless the server is restarted.
Reproduction
I started with the Ortus module template and have my tests running in the “test-harness” Coldbox application.
I have two tests in different test CFCs that interfere with each other when run together. All tests extend coldbox.system.testing.BaseTestCase
Test 1 – ClientProxyTest.cfc
...
beforeEach( function() {
variables.myApi = getInstance( "myApi@my-api-wrapper" );
prepareMock( variables.myApi );
} );
it( "should detect non-gateway methods using isGateway() convention", function() {
var mockResponse = {
"statusCode": "200",
"data": { "authenticated": "banana" }
};
variables.myApi.$( "whoami", mockResponse );
var proxy = getInstance(
name = "ClientProxy@my-api-wrapper",
initArguments = {
parentObject = variables.myApi,
methodName = "whoami",
methodArgs = {}
}
);
// Execute after WireBox injection
var result = proxy.execute();
expect( proxy.isImmediateMethodProxy() ).toBeTrue( "whoami is not a gateway, should execute immediately" );
expect( result ).toBeInstanceOf( "GatewayResult" );
} );
Test 2 – ApiTest.cfc
...
beforeEach( function(){
variables.myApi = getInstance( "myApi@my-api-wrapper" );
} );
it( "has whoami() method that delegates to echo gateway", function(){
prepareMock( variables.myApi.echo() ).$( "whoami" ).$results( { data : { user : "test" } } );
var result = variables.myApi.whoami();
debug( result ); <--- { "statusCode": "200","data": { "authenticated": "banana" } }
expect( result.data.user ).toBe( "test" ); <-- FAILS
expect( variables.myApi.echo().$once( "whoami" ) ).toBeTrue();
} );
- Each test passes when run individually
- When run together,
ApiTest.cfcreceives the mocked response fromClientProxyTest.cfc - Even more surprising:
- If I comment out
ClientProxyTest.cfcentirely - And re-run tests in a new request
- The mocked
"banana"value still persists when debugged - The only way to clear it is to restart the server
Things I Tried
this.unloadColdbox = truereset()inbeforeEach()andbeforeAll()- Testbox 5 and 6
Lucee 6 Result:
undefined tag [cfchart]; Failed in D:.…\my-api-wrapper\test-harness\coldbox\system\cache\report\skins\default\CacheCharting.cfm:5
Lucee 5 Result:
The key [MODULE_NAME] does not exist in the request scope, only the following keys are available: [$testid, cb_requestcontext, cbtransientdicache, coldboxvirtualapp, testbox]."
This behavior was surprising enough that I wanted to confirm whether I’m misunderstanding the lifecycle, or if this may indicate a bug or missing teardown step. Thanks in advance for any guidance.