Unit Testing: Testing Rejected Promises with Mocha

Unit Testing: Testing Rejected Promises with Mocha

Test Driven Development

Recently I have taken an interest in TDD(Test Driven Development). It seems to be a stimulating process of writing tests, first, before committing any lines of code to an application. Like most, I am used to the reverse- assuming I write unit tests in the first place. However, my curiosity is now asking if TDD is a step in the right direction for improving myself as a developer. This is what I discovered: a look into how TDD caused me to think about what my code specifically seeks to accomplish.

Why Testing With Mocha

In starting a recent NodeJS project I decided to change testing frameworks. I wish I could say that switching to Mocha from Jasmine was prompted by discovering some technical advantage from the former over the latter; but the truth is, I just wanted to put some new 'sauce' on a portfolio project.

In getting started with the docs I learned that the framework is not too different from what I was used to with Jasmine. From using 'Describe' to structure the test suite, to using 'it' to identify the actual tests, the similarity between the two allowed me to be able to quickly get started with writing tests.

Writing Unit Tests

In wanting to address some problems that I commonly have when creating a Node application, I decided it best to first test not properly connecting to a Mongo database. I hate when the most basic of things don't work. So I wrote the following unit test:

\the mongo_invalid_uri variable is assigned a ENV whose prefix is "mongodatabase://"- not "mongodb://" or "mongodb+srv://".*

After running my test script, Mocha output the following:

My test is failing(YES!) but it should be passing as a failure(whelp...). The reference error is a good pointer to what I need to address- define my error.

Admittedly, I rewrote the code with a try-catch block to get the error definition in the console.

While this code will work for my tests to pass, it got me thinking about if it was the best approach. I realized that I know this connection will fail. What's important is directly catching an intentional error; not unnecessarily trying my connection to see if mongo would connect.

As expected, Mocha passes with the try-catch statement:

And "console.error(error)" prints the error definition I need for my "assert.throws()" function.

I revert my code to its original implementation and include the error definition:

However, Mocha now gives me a brand new problem to address.

At this point, I realized I needed to 'get googly with it', and investigate why "assert.throws()" claimed an exception was missing. After a bit of reading, I discovered that the function couldn't catch any exceptions before mongoose "returned"; and, in sum, is not suitable for throwing errors on async functions.

The kind of function I needed would await mongoose's promise to complete and then would expect that promise to be rejected. I updated my code with "assert.rejects()":

and was given three Notre Dame Nikes with no errors on the play!

What I learned by taking on TDD, using three simple tests, is that it exposed me to consider what particular methods I would use to accomplish my goals in the code. Sure, I could use a try-catch statement in my unit test, but why would I do so if I already know the catch block is all that is needed? Also, it is important to fully understand the functions that a library/framework provides before making it a part of my implementation. So while "assert.throws()" is what I thought I needed; understanding its use more revealed that it was not suitable for the code I was testing.

After this exercise, I am very convinced that no code will be written on my part without a bit of Mocha or Jasmine dripped all over it. And this is certainly the direction an junior developer should take in becoming a more proficient developer.