DEV Community

Cover image for Code Smell 259 - Testing with External Resources
Maxi Contieri
Maxi Contieri

Posted on • Originally published at maximilianocontieri.com

Code Smell 259 - Testing with External Resources

Don't rely on things that can change without you noticing them

TL;DR: Tests must be in full control.

Problems

Solutions

  1. Generate the file in the test

  2. Mock it

  3. Use hardcoded streams instead

Context

Using an existing file for testing breaks the golden rule: tests must fully control their environment.

When someone changes the file, the test becomes erratic and unreliable.

That can result in an annoying debugging experience and non-deterministic test runs.

Sample Code

Wrong

const fs = require('fs');

function trimFile(data) {
    return data.trim();
}

// existing_file.txt holds the sample information
// "     John Wick    "

test('test process file', () => {
    const data = fs.readFileSync('existing_file.txt', 'utf8');
    expect(trimFile(data)).toBe('John Wick');
});
Enter fullscreen mode Exit fullscreen mode

Right

const fs = require('fs');
const { jest } = require('@jest/globals');

function trimFile(data) {
    return data.trim();
}

function generateTestData() {
    return ' John Wick ';
}

test('test process file generated', () => {
    const data = generateTestData();
    expect(trimFile(data)).toBe('John Wick');
});

test('test process file mocked', () => {
    jest.spyOn(fs, 'readFileSync').mockReturnValue(' mocked data ');
    const data = fs.readFileSync('file.txt', 'utf8');
    expect(trimFile(data)).toBe('John Wick');
    fs.readFileSync.mockRestore();
});
Enter fullscreen mode Exit fullscreen mode

Detection

[X] Automatic

You can detect this smell by identifying tests that rely on external files instead of generating or mocking the data.

Look for file path references and check if they are necessary.

Tags

  • Testing

Level

[X] Intermediate

AI Generation

AI generators might create this smell if they aren't given clear instructions to generate or mock test data instead of using external files.

AI Detection

GPT tools detect this smell if you guide them to check the code for external file dependencies.

Conclusion

Never use existing files and keep your tests runnable to a known state.

You need to generate your test data either by the test or mock it out completely so that tests are in full control.

Relations

More Info

Disclaimer

Code Smells are my opinion.

Credits

Photo by William Warby on Unsplash


Code without tests is broken by design.

Jacob Kaplan-Moss


This article is part of the CodeSmell Series.

Top comments (3)

Collapse
 
damian_cyrus profile image
Damian Cyrus

Hi @mcsee, I like to watch your series. It gives me so much insight and learning material, it is like a goldmine.

One point about comparing the values of files (or in general): ' John Wick ' is not the same as 'John Wick'.
I saw jest and vitest complain, that the value was not the same, if the value has spaces, because of strictness. These less strict tests are more like a ' John Wick '.includes('John Wick') to be true.

Another point: sometimes I have the feeling, that external data tests should go most of the time outside a unit test, like a E2E test. These unit tests scream at me to ignore it, because I need to mock data, and then I need to test the live code to expect a similar result. That are two tests for the same case, and that is why I find it questionable in most cases.

Of course, this depends on the testing case. 😉

Collapse
 
mcsee profile image
Maxi Contieri

Thank you Damian!
' John Wick ' is not the same as 'John Wick' in the real world. They represent different strings.
jest and vitest are right.

E2Etests (aka integration tests) should seed their own data, IMHO.
You need to have a lot of unit tests (fast) and several E2Etests (slow) . There is no problem with a bit overlapping

Collapse
 
alesisjoan profile image
Alesis Manzano

Hola Maxi, muy buenos tus artículos, estos están todos en tu libro?