Integration testing - mock the DAO

This question has come up a few times with no answers. Injecting mocked DAOs into an integration test seems a solution that would be great to find or engineer for.

I want to be able to mock the DAO so I can control the data that the test is trying to render on the view.
For instance, object ID 1 might be valid today, but if I run the test next month, the object may now be deleted or otherwise change status or other values. Useful for basic testing since I can inject needles into my mocked data that I can search for in the rendered results.

Is there a way to inject a mocked DAO into the mocked wirebox (or otherwise intercept the call to the DAO) so I can return controlled queries?

This would also be extremely useful to do integration testing on edit pages where I do not want the test to actually change data.

very simple sample execution path:

    in handler/main
        property name="user_service" inject="model:user_service";
        function list(event, rc, prc) {
            ... do some stuff ...
            arguments.prc.user_query = user_service.getUserQuery(user_id: arguments.event.getvalue('user_id', 0));
            ... do some other stuff to prep the view ...
        }


    in models/user_service
        property name="user_dao" inject="model:dao.user_dao";
        function getUserQuery(required numeric user_id) {
            return user_dao.getuserQuery(user_id: arguments.user_id);
        }

    in models/dao/user_dao
        function getUserQuery(required numeric user_id) {
            ... the actual database query I want to mock ...
        }

Any ideas?

1 Like

I’m sure others will chime in, but my recommendation is to step back one level and think about using a development database that you can develop and test against. In fact, if you leverage the commandbox-migrations module to “migrate up” and “migrate down” your dev/testing database, you can script in sample data to use for your testing and development purposes. Then you can leverage the cfmigrations module in ColdBox/TestBox to reload the sample data to start each relevant test suite (either unit or integration) and also roll back transactions between each test within the suite. This would eliminate the need to mock the DAO in your integration tests.

3 Likes

Everything @cfvonner said. That’s the way to go.

Doing mocking at this level will induce pain, time wasting and just really boring code to mock queries. This way might cause developer paralysis and make you stop testing entirely.

Leverage migrations and database fixtures and test all the way into the database.

Kudos @cfvonner !! I see the course skills where very well received indeed.

1 Like

I started with a test database but that was proving more problematic than I wanted, but it probably is the correct approach.

I’ve been using restoring backups of my production databases to my local dev environment to do testing. I’m going to start switching to using cfmigrations as time permits for two reasons:

  1. Production data changes, and at least a few times a year I have to fix tests that were depending on certain records existing that no longer exist.
  2. By “seeding” the dev/test database with data, I can make sure I add records that can simulate the “edge case” issues I encounter, so I can verify through testing that I’m properly handing those issues.

It will definitely take some time to build out the database “seed” scripts, but I think it will pay off in the long run.