DEV Community

Soham Thaker
Soham Thaker

Posted on

Adding tests to my project

Commit

3dfea570

Lab

Tasks completed for this week's lab:

  • Set up a testing environment for my codebase using Jest.
  • Wrote a few tests to introduce unit testing for my codebase which tested the core of the codebase.
  • Added a test runner to watch for code changes for the code or test cases to re-rerun the tests and also allow the ability to simply run a single test, a single test suite or a single test file.
  • Updated documentation file, CONTRIBUTING.md to add usage of testing.
  • Added code coverage to check for how many lines of code is tested using the testing framework.

Setting up Jest

  • Set up Jest by installing it as a dev dependency using the command npm install --save-dev jest. Then I added tests directory to write my tests.
  • Installed 3 dependencies, babel/core, babel/preset-env & babel-jest to make sure it supports the import syntax in test files and added babel.config.cjs config file with options.
  • Added jest: true to the env object located in .eslintrc.cjs file for ESLint to recognize jest's global variables like describe, it, etc.
  • Added test script which in turn runs jest --.

Writing first Jest tests

I picked a very small function to test its input and output. The function reads & parses TOML files using a third-party library. In one test suite, I wrote four tests, one of them testing the try path and the other three testing the catch part. It was somewhat of a hiccup to get these tests to set up because the code in the catch block performed console.error() and process.exit() operations. So I had to read the API to find out how to test these operations. That's when I stumbled upon mock functions spyOn() & mockImplementation(). Mock functions are also known as "spies", because they let you spy on the behaviour of a function that is called indirectly by some other code, rather than only testing the output. So I spied on the 2 operations and was able to match the result provided by the function, with the result that I was expecting written in the test cases. A code example is below,

it('function should exit with error message & exit code -1 with incorrect toml file path', () => {
    const mockStdErr = jest
      .spyOn(global.console, 'error')
      .mockImplementation(() => {});
    const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
    readAndParseTomlConfig('file/path/that/doesnt/exist.toml');

    expect(mockStdErr).toHaveBeenCalledWith(
      'Error reading or parsing TOML file'
    );
    expect(mockExit).toHaveBeenCalledWith(-1);
  });
Enter fullscreen mode Exit fullscreen mode

Allowing to run single tests and Test Runner Improvements

I added the capability to run a single file, test case or test suite using a single script npm run test:single blob. Here the blob argument can be a filename, test case or test suite. Also, I added the ability to have my test runner watch for changes and automatically run the tests when the test or source code is updated by using a single script npm run test:watch.

Test the Core

I added three tests part of the suite to test the core functionality of the project which is parsing MD to HTML. The three tests focus on testing the file I/O operations, specifically reading from a file, writing to a file and checking whether a file or directory exists. I added mock tests for it to simulate a real operation to test the functionality.

Adding code coverage analysis

Added code coverage analysis tool to test which files are tested and covered in testing and how much of the code is being missed out / tested on by running a single script npm run test:coverage.

Ignoring unnecessary folders

After running code coverage, it generates a folder named coverage. This folder is generated as a result of running a code coverage script. So there's no need to format, lint or commit the folder to GitHub. So I added the folder as part of .gitignore, .prettierignore & .eslintignore files.

Updating CONTRIBUTING.md

All of the above changes regarding tests have also been documented for ease of use.

Learning Outcomes

I understood the fundamental understanding of modern software testing practices by adding a test framework to my project. I learnt how to write concise and efficient test suites, create test cases for different parts of your codebase, and execute tests to ensure the functionality and reliability of my application. It also provided me with the skills needed to catch and address bugs early in the development process, leading to more robust and maintainable code since I was also fixing the code in the actual codebase while I was writing the tests for it. It gave me an understanding of advanced testing concepts like mocking, code coverage analysis, watching for test runner changes, etc. These skills will help me facilitate collaboration in a team, allowing me to be future-ready.

Top comments (0)