DEV Community

Ethan Carlsson
Ethan Carlsson

Posted on

Should you create new constants for tests

Yes and no. It depends on what you are testing.

If the constant is part of a public API it should probably be tested. But
otherwise you're just making your tests more flaky.

Where it makes sense

If you have

class Currency { 
    public static readonly EUROS = 'EUR'
}
Enter fullscreen mode Exit fullscreen mode

It might be acceptable to write a test like

test('Currency.EUROS is EUR', () => {
    expect(Currency.EUROS).toBe('EUR');
})
Enter fullscreen mode Exit fullscreen mode

In most cases this is overkill. But if your dealing with something where the
string of a currency matters a lot it might be make sense to write a test like this.

Where it doesn't make sense

It could be argued that you implicitly get the value of the test above by using
the constants directly inside other tests like this:

class CurrencyLocaleService {
    getCurrencyForLocale(locale: string): string {
        if (locale === Locale.SPAIN) {
            return Currency.EUROS
        }
        ...
    }
}

...
describe('CurrencyLocaleService', () => {
    const SPAIN_LOCALE = 'es_ES'

    const CURRENCY_EUR = 'EUR'

    test('getCurrencyForLocale with spain locale, returns euros', () => {
        const sut = new CurrencyLocaleService();
        expect(sut.getCurrencyForLocale(SPAIN_LOCALE)).toBe(CURRENCY_EUR);
    })
})
Enter fullscreen mode Exit fullscreen mode

This way we implicitly get the benefit of the first test. If the above test fails,
it will also mean that Currency.EUROS has been changed.

What's more we are also implicitly checking the correctness of Locale.SPAIN, so
if that ever changes this test will also fail.

In this way, the above test proves the correctness of the program a lot better than
this one:

describe('CurrencyLocaleService', () => {
    test('getCurrencyForLocale with spain locale, returns euros', () => {
        const sut = new CurrencyLocaleService();
        expect(sut.getCurrencyForLocale(Locale.SPAIN)).toBe(Currency.EUROS);
    })
})
Enter fullscreen mode Exit fullscreen mode

However, I like this test better because it only tests the one thing. We might have
a legitimate reason to change the values of these constants, maybe some external
API needs currency to be in lower case 'eur'. If that's the case then a test
that checks that getCurrencyForLocale with spain locale, returns euros should not
fail, because while the string has changed Currency.EUROS still means the same thing.

Maybe we will need to change our first test to this

test('Currency.EUROS is eur', () => {
    expect(Currency.EUROS).toBe('eur');
})
Enter fullscreen mode Exit fullscreen mode

But not both tests.

Tests aren't really about proving that your code is correct

I think the reason people like to write tests like this

describe('CurrencyLocaleService', () => {
    const SPAIN_LOCALE = 'es_ES'

    const CURRENCY_EUR = 'EUR'

    test('getCurrencyForLocale with spain locale, returns euros', () => {
        const sut = new CurrencyLocaleService();
        expect(sut.getCurrencyForLocale(SPAIN_LOCALE)).toBe(CURRENCY_EUR);
    })
})
Enter fullscreen mode Exit fullscreen mode

Is the belief that the goal of our tests exist to show correctness and protect
the code from becoming incorrect. If someone comes along and changes the value
of Currency.EURO all our tests will fail and there's no chance that the code
will make it to production.

However, we will need to change the code, and that doesn't mean that the code is now
wrong.

Tests aren't really about showing that your code is correct, I don't think. They're
about expressing what we expect our code to do. If I make a change to existing
code the tests should fail, but only to the extent that our expectations have changed.

If I change Locale.SPAIN from 'es_ES' to 'es-ES', this test should fail

test('Locale.SPAIN is "es_ES"', () => {
    expect(Locale.SPAIN).toBe('es-ES');
})
Enter fullscreen mode Exit fullscreen mode

if it exists, because the expectation changed. But no other test should fail.

Original article: https://www.ethancarlsson.dev/blog/constantsintests

Top comments (0)