Should you create new constants for tests
Tags: testing, javascript, typescript, programming
Published: 2022-08-10 18:02:28

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 

```typescript
class Currency { 
    public static readonly EUROS = 'EUR'
}
```

It might be acceptable to write a test like

```typescript
test('Currency.EUROS is EUR', () => {
    expect(Currency.EUROS).toBe('EUR');
})
```

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:
```typescript
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);
    })
})
```
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:
```typescript
describe('CurrencyLocaleService', () => {
    test('getCurrencyForLocale with spain locale, returns euros', () => {
        const sut = new CurrencyLocaleService();
        expect(sut.getCurrencyForLocale(Locale.SPAIN)).toBe(Currency.EUROS);
    })
})
```
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
```typescript
test('Currency.EUROS is eur', () => {
    expect(Currency.EUROS).toBe('eur');
})
```
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
```typescript
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);
    })
})
```
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

```typescript
test('Locale.SPAIN is "es_ES"', () => {
    expect(Locale.SPAIN).toBe('es-ES');
})
```
if it exists, because the expectation changed. But no other test should fail. 

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