[ColdBox 4.3.0] CF2016 [Testbox 2.6.0] Cannot load component dependencies in Testbox

I am testing a service in Testbox and get an error to load the DAO dependency injected by wirebox in the service. Here is the test:

component extends=“coldbox.system.testing.BaseTestCase” appMapping="/" {

/*********************************** LIFE CYCLE Methods ***********************************/

function beforeAll(){
super.beforeAll();

//Create the service to test, do not remove methods, just prepare for mocking.
geozoneService = createMock(“models.crd.GeozoneSVC”);

// Mock the entity bean
mockBean = createEmptyMock(className=“models.crd.Geozone”);

// Mock the DAO object
mockDAO = createMock(className=‘models.crd.GeozoneDAO’);

// Mock the Gateway object
mockGW = createMock(className=“models.crd.GeozonesGW”);

//Init the service with mock dependencies
geozoneService.init(mockBean,mockDAO,mockGW);

}

function afterAll(){
// do your own stuff here
super.afterAll();
}

/*********************************** BDD SUITES ***********************************/

function run(){

describe( “Geozone service”, function(){

aroundEach( function( spec, suite ){

transaction action=“begin”{

try{

// execute the spec

arguments.spec.body();

} catch( Any e ){

rethrow;

} finally {

transaction action=“rollback”;

// Empty the databean target instance after each specification run

var databean = “”;

}

}
} );

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

it(“can read a geozone record”, function(){

mockBean.setGeozoneID(18);
mockBean.setGeozoneName(“SOUTH EAST ASIA”);
mockBean.setGeozoneWestOffset(25200);
mockBean.setGeozoneEastOffset(28800);

// Create an instance of the target bean to hold the simulated data

dataBean = createObject(‘component’, ‘models.crd.Geozone’).init();

// This test must succeed.
// Populate dataBean with the data returned by the read method.
// expect mockBean to match dataBean

databean = geozoneService.read(18);

expect( databean.getGeozoneID() ).toBe( mockBean.getGeozoneID() );
expect( databean.getGeozoneName() ).toBe( mockBean.getGeozoneName() );
expect( databean.getGeozoneWestOffset() ).toBe( mockBean.getGeozoneWestOffset() );
expect( databean.getGeozoneEastOffset() ).toBe( mockBean.getGeozoneEastOffset() );

});

In the service, I have injected the DAO as follows:

component singleton accessors=“true”{

// Dependency Injection

property name=“dao” inject=“models.crd.GeozoneDAO”;
property name=“gw” inject=“models.crd.GeozonesGW”;

property name=“objGMT” inject=“models.utils.datetime.GMTconvSVC”;

property name=“log” inject=“logbox:logger:{this}”;
property name=“populator” inject=“wirebox:populator”;
property name=“wirebox” inject=“wirebox”;

function init(){
return this;

}

}

The test results are attached.

What am I missing?

I am testing a service in Testbox and get an error to load the DAO dependency injected by wirebox in the service. Here is the test that I have just modified to include

application.wirebox = new coldbox.system.ioc.Injector() in the beforeEach() function.

You are trying to pass your mocked dependencies in the init() constructor but you are not doing constructor injection. You are doing property injection in this case. So to inject mocked properties, use $property().

geozoneService.$property(propertyName="dao",mock=mockDAO)

You will actually have to do that for each property (including log, wirebox & populator)

`

mockLogger = mockBox.createEmptyMock( “coldbox.system.logging.Logger” );
mockWireBox = mockBox.createMock( “coldbox.system.ioc.Injector” ).init();

`

Thanks for the feedback Pascal! I was not aware of this subtle requirement for mocking dependencies. I am going to modify my tests accordingly.

Now it seems my unit test is working with the latest version of this test herein below:

component extends=“coldbox.system.testing.BaseTestCase” appMapping="/"{

/*********************************** LIFE CYCLE Methods ***********************************/

function beforeAll(){
super.beforeAll();

// Get an instance of the service component for testing

geozoneSVC = getInstance( “GeozoneSVC” );

}

function afterAll(){
super.afterAll();
}

/*********************************** BDD SUITES ***********************************/

function run(){

describe( “Geozone service unit tests Suite”, function(){

aroundEach( function( spec, suite ){

transaction action=“begin”{

try{

// execute the spec

arguments.spec.body();

} catch( Any e ){

rethrow;

} finally {

transaction action=“rollback”;

// Empty the databean target instance after each specification run

var databean = “”;

}

}
} );

it(“can read a geozone record”, function(){

// Mock a new entity bean
mockBean = createMock(“models.crd.Geozone”);

mockBean.setGeozoneID(18);
mockBean.setGeozoneName(“SOUTH EAST ASIA”);
mockBean.setGeozoneWestOffset(25200);
mockBean.setGeozoneEastOffset(28800);

// Populate a data bean with the data returned by the read method.
// expect mockBean to match dataBean

var databean = geozoneSVC.read(18);

expect( databean.getGeozoneID() ).toBe( mockBean.getGeozoneID() );
expect( databean.getGeozoneName() ).toBe( mockBean.getGeozoneName() );
expect( databean.getGeozoneWestOffset() ).toBe( mockBean.getGeozoneWestOffset() );
expect( databean.getGeozoneEastOffset() ).toBe( mockBean.getGeozoneEastOffset() );

});

it(“can create a geozone record”, function(){

// Mock a new entity bean
mockBean = createMock(“models.crd.Geozone”);

mockBean.setGeozoneName(“TEST”);
mockBean.setGeozoneWestOffset(-3600);
mockBean.setGeozoneEastOffset(3600);

// Simulate FORM data inserts

insertFormData = structNew();

insertFormData.geozoneName = “TEST”;
insertFormData.geozoneWestOffset = -3600;
insertFormData.geozoneEastOffset = 3600;

var dataBean = createObject(‘component’, ‘models.crd.Geozone’).init(
argumentCollection=insertFormData);

// Populate dataBean with the data returned by the create method.
// expect mockBean to match dataBean

var iNewID = geozoneSVC.create(Geozone=dataBean);
dataBean.setGeozoneID(iNewID);

expect( dataBean.getGeozoneID() ).toBe( iNewID );
expect( dataBean.getGeozoneName() ).toBe( mockBean.getGeozoneName() );
expect( dataBean.getGeozoneWestOffset() ).toBe( mockBean.getGeozoneWestOffset() );
expect( dataBean.getGeozoneEastOffset() ).toBe( mockBean.getGeozoneEastOffset() );

});

it(“cannot duplicate a geozone name”, function(){

// Mock a new entity bean
mockBean = createMock(“models.crd.Geozone”);

// The geozone name “SOUTH EAST ASIA” already exists and cannot be duplicated

mockBean.setGeozoneName(“SOUTH EAST ASIA”);
mockBean.setGeozoneWestOffset(0);
mockBean.setGeozoneEastOffset(7200);

// Simulate FORM data inserts

insertFormData = structNew();

insertFormData.geozoneName = “SOUTH EAST ASIA”;
insertFormData.geozoneWestOffset = 0;
insertFormData.geozoneEastOffset = 7200;

var dataBean = createObject(‘component’, ‘models.crd.Geozone’).init(
argumentCollection=insertFormData);

// This test must fail.
// a new geozone cannot be given an existing name.

try {

var iNewID = geozoneSVC.create(Geozone=dataBean);
dataBean.setGeozoneID(iNewID);

} catch(database e) {

// This test must return a database error: SqlState = 23000 , ErrorCode = 1062
// Duplicate entry for composite key ‘UNIQUE’.

expect( e.Message ).toInclude ( “UNIQUE” );
//expect( e.SqlState ).toBe( “23000”);
//expect( e.Detail ).toInclude ( “UNIQUE” );

}

});

});

}

}

However, I still encounter an issue with the last test in the suite (see attached Testbox result) where I am testing for a database insert failure. I used to be able to capture the SqlState and the Detail of the exception error message to build my expectations. But somehow, this does not work any more… According to the testbox result attached, it seems that the only member of the exception structure populated with the expected SQL error statement is “Message”. But I still cannot include part of this message to validate my exceptions. Any suggestions?

This issue is now solved. The test function was modified as follows:

it(“cannot duplicate a geozone name”, function(){

// Mock a new entity bean
mockBean = createMock(“models.crd.Geozone”);

// The geozone name “SOUTH EAST ASIA” already exists and cannot be duplicated

mockBean.setGeozoneName(“SOUTH EAST ASIA”);
mockBean.setGeozoneWestOffset(0);
mockBean.setGeozoneEastOffset(7200);

// Simulate FORM data inserts

insertFormData = structNew();

insertFormData.geozoneName = “SOUTH EAST ASIA”;
insertFormData.geozoneWestOffset = 0;
insertFormData.geozoneEastOffset = 7200;

var dataBean = createObject(‘component’, ‘models.crd.Geozone’).init(
argumentCollection=insertFormData);

// This test must fail.
// a new geozone cannot be given an existing name.

try {

var iNewID = geozoneSVC.create(Geozone=dataBean);
dataBean.setGeozoneID(iNewID);

} catch(DBinsertError e) {

// This test must return a database error: SqlState = 23000 , ErrorCode = 1062
// Duplicate entry for composite key ‘UNIQUE’.

expect( e.Message ).toInclude ( “UNIQUE” );
//expect( e.SqlState ).toBe( “23000”);
//expect( e.Detail ).toInclude ( “UNIQUE” );

}

});

I just needed to refer to the exception named “DBInsertError” thrown by my DAO for the mySQL error message to be properly evaluated by the expectation. The suite is now successfully tested as shown in the attached testBoxResult3.