revy
revy

Reputation: 4707

Properly write integration tests for database population logic

I have an event handler written in node which should populate several MySQL tables as a result of a single transaction (meaning that all the operations should complete correctly or otherwise everything must be rollbacked to the initial state). I have some doubts about the correct way to write integration tests in this case. The followings are some possible scenarios I was thinking:

1) Run the population logic in a before all tests phase and then run individual tests on tables, then cleanup everything in a after all tests phase.

describe('test', function() {
    before(async () => {
        // run event handler to populate database
    });

    after(async() => {
        // cleanup
    });

    it('test Table A', () => {  })

    it('test Table B', () => {  })

    it('test Table C', () => {  })
});

2) Run population logic and cleanup before and after each test respectively.

describe('test', function() {
    beforeEach(async () => {
        // run event handler to populate database
    });

    afterEach(async() => {
        // cleanup
    });

    it('test Table A', () => {  })

    it('test Table B', () => {  })

    it('test Table C', () => {  })
});

3) Test everything in one single test.

describe('test', function() {
    before(async () => {
        // just open the db connection
    });

    after(async() => {
        // cleanup
    });

    it('populate db and test every table', () => {  })
});

There are other possible scenarios as well. I would like to know which is the better way to go and why.

ps: I am using mocha and chai for testing but the question should be language agnostic.

Upvotes: 0

Views: 199

Answers (2)

Charles Salmon
Charles Salmon

Reputation: 467

I tend to use before, after, beforeEach and afterEach hooks sparingly, because they create coupling between tests and can blur the intent of a test if all of the setup/teardown is not necessarily relevant to the test.

Given that you are testing the result of executing a transaction, I would opt for usage of the before / after hooks, to ensure that you do not need to execute and rollback the transaction before each test. I would continue on to write tests which make a single assertion each (as opposed to having a test per table), to ensure that the tests communicate their intent clearly. I would also ensure that each test does not perform any form of mutation that could have an effect on the results of another test.

Upvotes: 1

isick
isick

Reputation: 1487

I'm using jest so it might be different, but jest has test-wide setup and teardown hooks which I use to clone the production database structure and then clear data respectively. Then I use each suite's before/after and each tests before/after (beforeEach/afterEach) to setup and teardown only test-specific data.

This means the most costly step (setting up tables and relations) is only done once at start, and I'm still able to semantically split up my tests into the proper verticals.

Upvotes: 1

Related Questions