The main tests to write are tests for properly working code. But in some situations, the code has to return errors, and these too may need to be checked. Errors are situations where the code throws an exception. What features do they have? Look at this test:
test('boom!', () => {
try {
functionWithException(0);
} catch (e) {
expect(e).not.toBeNull();
}
});
This code is trying to test a situation where functionWithException()
throws an exception if you pass it 0. Do you think this test will verify that the function actually generates an exception?
The correct answer is no. If functionWithException()
doesn't throw an exception, the test passes because the code doesn't get into the catch
block.
Jest's documentation offers its own way of testing such situations. Jest allows you to specify the number of statements to be executed in the test. If this doesn't happen, Jest reports an error:
test('boom!', () => {
// Number of statements to be run in this test
expect.assertions(1);
try {
functionWithException(0);
} catch (e) {
expect(e).not.toBeNull();
}
});
This method is extremely dangerous. It generates flimsy tests that are tied to the way they are written. If you want to add a new statement, the test will fail, and you'll have to modify it. You will always have to make sure that this number is correct. Don't use this approach, the more contextual dependencies there are, the harder it is to figure out the code, and the easier it is to make mistakes.
And now we'll get to the proper way. Jest has a matcher that independently catches the exception and checks that it was actually generated.
test('boom!', () => {
expect(() => {
functionWithException(0);
}).toThrow();
});
The main feature of this matcher is that it takes a function that's called internally as input. Thanks to this, it can independently track when the exception appears. This code contains no implicit state and no unnecessary checks. It does exactly what needs to be done and doesn't require too much from us. Moreover, it's theoretically possible to have a test in which several checks for various exceptions are made at once. This is much harder to pull off with the previous methods.
Sometimes, it's important not just to catch an exception, but also to make sure that it's an expected exception. This can be done by passing a string that must be present in the exception message to the toThrow()
matcher, so you can check that the error message appears.
test('boom!', () => {
expect(() => {
functionWithException(0);
}).toThrow('divide by zero');
});
Recommended materials
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.