dimanche 28 mars 2021

Can we use functions to arrange unit test so that we can reuse it?

I have read several posts online that unit tests should be independent.

However, this significantly increases the amount of code and we have a lot of repetition.

This is an illustration:

describe('Magic Calculator', () => {
    let param1:any;
    let param2:any;
    let param3:any;
    function arrangeDefault () {
        param1 = {
            foo1: 1, foo2: 2, foo3: 3, // ... 
        }
        param2 = {
            foo1: 1, foo2: 2, foo3: 3, // ... 
        }
        param3 = {
            foo1: 1, foo2: 2, foo3: 3, // ... 
        }
    }

    it('should work for most common case', () => {
        arrangeDefault();
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(200);
    })
    it('should work for edge case 1', () => {
        arrangeDefault();
        param1.foo1 = -1
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(500);
    })

    it('should work for edge case 2', () => {
        arrangeDefault();
        param1.foo1 = 0
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(503);
    })

    it('should work for edge case 3', () => {
        arrangeDefault();
        param1.foo1 = null
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(401);
    })

})

As you noticed, every test case uses a common arrange function arrangeDefault. This decreases significantly the amount of code required, and it is much cleaner at the time of the writing. But several months later, one of these test case fails, it takes so much time to understand why the test case is failing. That's because we have to do a lot of declaration finding, trying to understand what changed the states of the param, understanding how the code fits together, until we can know what the bug is.

So if I follow the advice of the posts that I read online, the test code should look like this:

describe('Magic Calculator', () => {


    it('should work for most common case', () => {
        let param1 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        let param2 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        let param3 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(200);
    })
    it('should work for edge case 1', () => {
        let param1 = {
            foo1: -1, foo2: 2, foo3: 3, // ...
        }
        let param2 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        let param3 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(500);
    })

    it('should work for edge case 2', () => {
        let param1 = {
            foo1: 0, foo2: 2, foo3: 3, // ...
        }
        let param2 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        let param3 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(503);
    })

    it('should work for edge case 3', () => {
        let param1 = {
            foo1: null, foo2: 2, foo3: 3, // ...
        }
        let param2 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        let param3 = {
            foo1: 1, foo2: 2, foo3: 3, // ...
        }
        const result = MagicCalculator(param1, param2, param3)
        expect(result.value).equal(401);
    })

})

But now we have a lot of repetition, and this is just an illustration, the actual code has way more parameters for the setup. so what is the correct way to do things ? Where is the root cause of my problem ?

Aucun commentaire:

Enregistrer un commentaire