Hello, my fellow developers.
In my previous post, I wrote about how to develop a simple and easy tool for generating keys for you to use in your projects.
As I wanted to publish it as a package on npmjs.com, I needed to write some tests to ensure everything was running smoothly in every situation.
Picture this: You've spent some time crafting a TypeScript library, meticulously designing its features. However, before you unleash your creation upon the world, you need to ensure that it's as robust as a tank and as reliable as your grandma's secret cookie recipe, right?
So I chose Jest.js, the trusty sidekick of TypeScript developers, ready to assist in the quest for bulletproof code.
In this post, we're going to start crafting a series of unit tests using Jest.js to ensure our Key Generator tool behaves impeccably.
I decided to split this into a 2-part article because it ended up being too long.
Testing the validateGroupFormat
method
Our first group of tests will focus on our private method validateGroupFormat
, guaranteeing it throw the errors when needed.
Let's start by setting the stage for our tests by writing 2 describe
s, thus creating 2 context blocks for our actual tests.
import CodeGenerator, { ICodeGenerator } from "../index";
describe("Key Generator Tests", () => {
describe("Testing 'validateGroupFormat' errors and warnings'", () => {
let sut: ICodeGenerator;
// Our tests will be written here.
[...]
});
});
Don't forget to import our dependencies: the CodeGenerator
class and our interface ICodeGenerator
, since our sut
(system under test) should have this type.
Also, we are not going to call the actual validateGroupFormat
, but test its functionality by actual calling our generate
method.
Now, let's see our first test.
Empty groupFormat
When a developer uses the CodeGenerator class without specifying the groupFormat, we don't want to pester them with unnecessary validation checks. Instead, we choose to be polite and silently skip the validation process.
it("Should skip validation if 'groupFormat' was not informed by the user", () => {
sut = new CodeGenerator(5);
const consoleSpy = jest.spyOn(console, "log");
sut.generate();
expect(consoleSpy).toHaveBeenCalledWith("Group Format is not defined, skipping validation.");
});
If you don't remember or didn't read my last post, I suggest you take a quick look at it by clicking here so you can get familiar with the code being tested.
So, when the groupFormat
is empty this validation will simply call a console.log with the message 'Group Format is not defined, skipping validation.'.
Therefore, we used the 'spyOn' method on Jest to watch if the "log" method of the console
was being called when we generate a new code.
You may be wondering why we even called our validateGroupFormat
auxiliary method in the first place if the user did not inform the groupFormat
property.
Well, we did this to comply with the first principle of SOLID: single responsibility. We could have actually checked if the groupFormat
was empty before calling the validation method, but that would mean the generate
method would also be doing its own validations, and this can get confusing. Of course this is a very small project, but it's important to follow a clean code pattern even when we are working on small pieces of code, so others (and your future self) can properly understand what the code is doing.
With that clear, let's jump to the other test.
groupFormat
being passed with the wrong type of characterType
The groupFormat
purpose is to let the user customize the order of characters (Letters or Numbers) in the output key.
it("Should throw an error when 'groupFormat' is used with 'characterType' other than 'LettersAndNumbers'", () => {
sut = new CodeGenerator(5, { characterType: "Letters", groupFormat: "NNLNL", });
expect(() => sut.generate()).toThrow(
new Error("The groupFormat can only be used with 'LettersAndNumbers' characterType!"),
);
});
So, in our second test, we don our detective hats to catch developers trying to mix incompatible options. Thus, we test by passing "Letters"
to characterType
property and at the same time we configure our output to have a groupFormat
of "NNLNL"
.
The test is pretty simple. It ensures that our code enforces rules consistently, preventing developers from using incompatible settings that could lead to unexpected behavior.
One thing to notice here is that we have called sut.generate
inside a anonymous function. If you don't do that, the test will not run due the Error
being actually thrown.
groupFormat
contains invalid characters
The third and final test for our validation method is all about maintaining order on our key generation tool. We won't tolerate any rogue characters sneaking into the groupFormat
. If a developer dares to include characters other than 'L' (for letters) or 'N' (for numbers), our code will not hesitate to raise the alarm.
The code for our test is the following:
it("Should throw error when 'groupFormat' has any characters other than 'L' or 'N'", () => {
sut = new CodeGenerator(5, {
characterType: "LettersAndNumbers",
groupFormat: "LLLLB",
});
expect(() => sut.generate()).toThrow(
new Error("The group format can only contain letters 'L' and numbers 'N'"),
);
});
The validation here is similar to the one being made in the previous test.
Our validation method is using a RegEx statement to match our string, as seen in the previous post.
Here we passed the string "LLLLB"
, so our code successfully throws an error when trying to generate a key.
generate
method
To void making this post too long, I will place only the first test for the generate
method. The second part is going to address the rest of the tests.
Generating a random key with the default settings
What a better way of starting our tests for the generate
method if not by actual generating a key, right?
We are going to start with the default settings (no props being passed).
it("Should generate a random code with the default options", () => {
sut = new CodeGenerator(5);
const randomSpy = jest.spyOn(Math, "random");
const code = sut.generate();
expect(randomSpy).toHaveBeenCalledTimes(code[0]!.length);
expect(code).toHaveLength(1);
expect(code[0]).toHaveLength(5);
});
Here we are asking our "System Under Test" to generate a 5-character key.
We're also using Jest's spyOn
to watch on the random
method of the Math
library.
Our code
, which is an Array, should have a length of 1 and the length of the key needs to be of 5 characters. Hence, logic requires that the random
method is being called 5 times as well.
In the next post, which is going live a few hours after this one, we are going to address the rest of our tests.
Hope y'all enjoyed this first part.
I'll be glad to read your thoughts.
Top comments (0)