Writing Tests For Mongo/Mongoose with Mocha
It’s been a while since my last post, but I thought I’d come back and write about something that I’ve been having some fun diving into. I’ve been practicing coding out some basic CRUD tests for MongoDB while following Stephen Grider’s Udemy course “The Complete Developers Guide to MongoDB”. I recommend everyone go and check it out.
Mongo is my favorite database to work in and I feel totally comfortable using it, but I’m always looking to learn anything I can. One thing I was looking to gain more practice in was writing unit tests for Mongo.
Writing good unit tests is an aspect of programming that I constantly try to better myself at, as I think everyone should. I’ve worked on a couple projects recently, and I’ll admit that when working on a project where I’m the only one coding, I don’t dive into writing tests. However, when thinking about the possibility of passing the code on to a new programmer coming in, this is where I think writing tests is very important.
So here is a basic rundown of a starter test for MongoDB. The only packages we’re going to be using that need to be installed via NPM are Mongoose and Mocha. I’ll be using ES6 fat arrow functions and promises, but I’ll be doing my requires and variables with ES2015.
Before we write tests, we’ll do a basic schema set up. You can see the file structure on the left, which shows that we’re in a “src” directory that contains a file named “users.js”. In this file, we set up our User schema.
For the purposes of creating basic tests, this is really all we need. We’ve set up a basic UserSchema with a name property of type String, we’ve set the model to a variable User, and exported it. This is what we’ll require into our tests. Using this set up, we can create a user, read the user, update the user and delete (remove) the user.
Now, below is a helper file setup in a “test” directory. This is where we’ll actually connect to our database using Mongoose.
There are a few cool things going on here. We’re using the ES6 import at the top to import mongoose into the file. The next line is one that I find really awesome. I have been seeing a deprecation warning while using Mongoose for some time now. If you’ve seen that warning and had no idea how to fix it, this is a super easy way to fix it. Since promises comes with ES6 now, we’re able to simply assign global.Promise to mongoose.Promise, and mongoose will use ES6 promises. Voila. No more deprecation warning.
Next, before we run our tests with Mocha, we’re going to connect to our Mongo database. We pass in “done” as an argument, and upon a successful connection, we call it in our callback so Mocha can move on. If an error occurs, we have it go to our console so we can see what happened. Assuming there’s no error, Mocha then moves down to our beforeEach hook. In here, we’re telling Mongoose to drop our user collection so that each time we run a test, we’re starting with a fresh, empty collection. Then in our callback, we call “done()”. Mocha then moves on to our tests.
For this post, I think I’m only going to test the “create” portion of CRUD, but I might do later posts going into the read, update, and delete pieces. You can see those files on the left in this image, along with a validation test file. In the image below, you see our test file for “create”, named “create_test.js”. I have a linter error but ignore that! :)
So at the top here we’re requiring “assert” from Node.js, since Mocha doesn’t come with it, and our User schema. We then create a describe block. This is the top level block of your test. This is where you will describe your main reason for the test. In this case, “Creating records”. Therefore, all of the tests within this block are going to relate to creating records. Then, within the callback, we make an “it” block. We first pass in something that “it” should do. “It” (our code that we’re testing) should save a user. Simple enough. So, within the “it” block callback, we’re going to code out our actual test.
We set up the test by creating a variable “dan”, and setting it equal to a new user, using the User schema we created earlier. We just pass in an object with a name property, and for the value we type a name like “Dan”. So we have this newly created user variable “dan”, and it’s following our User schema, but we haven’t saved it to the database yet. So we call “dan.save()” to do that. Then, using promises, upon the save successfully resolving we actually run our test calling “assert()”.
We use “assert” by making an “assertion” that what we pass in will evaluate to true. We can use the Mongoose provided property “isNew” on our user to see if it’s actually be successfully saved or not. After our “dan.save()” call, isNew will actually return false, so we add the exclamation point before “dan.isNew” to get the opposite boolean value. What we’re actually wanting to assert is that the user “dan” is “not new”. We then call done to finish up the test, telling Mocha to move on.
Now we’re ready to run our test. If you navigate to your top level project directory in your terminal and run “mocha”, you should see Mocha do its thing and a passing test!
Though it’s very basic, that is unit testing in a nutshell. We tested one specific piece of code and got it to pass. The saying is “Red, Green, Refactor”. So you’ll write a failing test, make it pass, and then refactor the code. This is what a failing test looks like:
So, another programmer could easily come in, run the tests, see the details and pick up where you left off. If you’re working solo, then it’s a great way to make sure that any new code you’re working on hasn’t broken anything. It’s definitely a great habit to pick up. Thanks for reading!