The time has finally come to test our work! This week, we were asked to introduce a testing framework into our project and to write tests!
My go-to was Jest, particularly because I hadn't used Jest to mock services before and was curious how it would work. Of course, I had to install the TypeScript version of Jest and an ESLint plugin, but soon after, Jest was installed and running.
Jest is arguably one of the most popular, if not the most widely used, testing frameworks for JavaScript and TypeScript. It seemed only right to deepen my knowledge of its mocking capabilities for this project.
Setting up Jest was straightforward and hassle-free. Simply install the package, its TypeScript types, and voilà, it works. However, as I mentioned, since I use ESLint, I also had to install the Jest ESLint plugin so that ESLint recognizes the types without requiring explicit imports everywhere.
Testing
Thankfully, when I started developing OptimizeIt
, one of my primary concerns was how to make it modular, scalable, and testable. The answer, of course, is separation of concerns and smaller functions. Unlike the code I used to write several years ago, I now consider several factors when coding. One of these for this project was ensuring that complex logic remained simple enough to be both performant and easily tested.
This made the testing process much easier; I ended up with standalone test files for each small piece of functionality in my entire project, including the Groq chat completion API!
I was pleasantly surprised to see that I hadn’t missed any edge cases. I tried to be as thorough as possible when testing each function: How could it break? What would happen if I did this? What would happen if I used incorrect data? Thankfully, everything worked as expected.
As for testing the chat completion API provided by Groq, my approach was pretty simple: Get the actual response JSON format, mock it, mock the chat completion API, and test!
I ended up with a thorough test suite for the heart of my project—the chat completion functionality—and it worked just as expected.
After several hours of writing tests, I achieved a pretty solid 96% code coverage!
Now, I have a lot of experience with testing from previous courses, personal projects, and my job. In my job, I've thoroughly tested and mocked several tricky cloud provider services. Testing OptimizeIt was straightforward, though I was initially a bit stuck figuring out how to start the mocking process with Jest
since Jappa/Runner
, the tool I use at work, simplifies this process.
Finally, I added a couple of extremely helpful scripts to OptimizeIt: one that runs tests whenever source code changes, one that calculates code coverage and generates a report in the coverage
folder, and one particularly useful script that allows you to run a single test file! Then, I added a new job to my CI workflow that runs all the tests.
Summary
This week’s task was substantial; it’s not easy or quick to write tests that maintain high coverage (80%+) for a project with this much functionality. However, it was a great learning experience. Writing tests always helps improve the way you write code. It helps you catch edge cases you hadn’t thought of or small logical issues, like an &&
instead of an ||
, that could cause a problem if not caught.
While it's impossible to catch every edge case, I believe there's always that one edge case you don't think of that could break your code. This is one reason why versions exist in projects—no one can make something perfect right off the bat, though perhaps over time!
Personally, what I valued most from this was keeping the source code simple. Not only does this make it more readable, but also much, much easier to test!