Unit testing in Node.js is very similar to unit testing in the browser, except for the absence of the DOM. To make the testing process easier, Scott recommends exporting the main application so it can be used by the testing framework. He also covers a couple of strategies for writing API tests and saving development dependencies.
[Ambient Music] - (Scott Moss) So, if you want to check out, see step 5 Yeah, that's it We'll hop into testing, but before I set you loose and actually start writing some tests for the lions and tigers API that we built, let's just walk through what testing is and how it works with Node and Mongo and the different types of testing and what we're actually going to be testing and stuff like that. So, testing is actually pretty simple in Node in my opinion actually from testing other languages and other environments. In Node it was pretty straightforward compared to other things like tests for android or something like that Node is actually pretty simple.
So unit tests are very similar to how you would test in the browser minus the DOM. So if we were going to unit test our job using Node, it would be the exact, pretty much the exact same thing if you were testing in the browser without the DOM So like for instance if you were riding tests for a browser code four/five years ago, before karma came along and all the other stuff you would you know, use Mocha or Jasmine, probably not Mocha but something like Jasmine it'll generate like a HTML file for you where you loaded up all your specs and loaded up all your source code, loaded up all your dependencies and when you opened that file in the browser and you run it, the tests sweep through there and have a nice UI right, and then Karma came along and it's like "Oh we're going to build from the from the command line now and we'll just pipe it to the browser".
So yeah, we're going to be doing integration testing mainly because the code that we've written so far, we haven't written a lot of code, actually most of the code that we have written is part of Express So we start unit testing we'll just be unit testing with Express' already doing, and that's already well tested. So we'll just be doing integration testing to see what our API responds to when we throw different parameters at it and what we expect to come back too. So, any questions so far on that?... Yes - [Offscreen] Is integration testing a synonym for BDD? - [Scott] Behaviour Driven Development? I wouldn't say it's a synonym, it's part of BDD but I definitely wouldn't say it's a synonym, BDD is more than just integration testing, it's just, BDD is like a style of testing versus TDD is like Test Driven Development where like you got to write some tests first it's like red/green refactor with TDD, write a whole bunch of tests, and then have the tests tell you what codes were right to do in the past.
BDD is more like, you know, we expect this thing to happen and so we're like going to write a test to, you know, dictate this entire behaviour, but yeah integration testing is part of BDD but they're not the same thing. Integration testing is a type of test BDD is how you write your test. Great, so a good practice with Node and Express and integration testing from what I've witnessed is if you export the app before you're starting it, so like in our application, that we wrote yesterday we were at the bottom of the file down here, we were like app dot listen, right we're listening to some port or something, alright that's how you start the server, when we're testing it a good practice is actually just to instead of listening to the server right there on that same file, is just to export the app.
So it can be required somewhere else, I'll show you why that makes sense. But the big reason is really so that our tests can actually use that app and all the routes on it to make assertions and go ahead and start the server for us. So if we just export the app before starting it we can actually just run the tests without having to start the server manually, we can have the test do it for us. So what I'm saying is, like with several routes like this and then at the bottom we would just export the app. So that also implies that we'd have to make another file that would import this and start the server , of course.
Which is, as you'll see, is actually pretty good once you see we'll start making a pretty sophisticated API. It's a good practice as well. Any questions on that? Does that not make sense to anybody? Why I think exporting the app is a good idea? We want to expose our entire server application to, like, our testing framework, so if I exported I could do that. You can also just start the server too and then export the app there's nothing wrong with that, but I would just leave it up to my tests to figure out what it wants to do.
Like maybe the test wants to start the server with a different port, or a different configuration, stuff like that. So, strategies for actually testing your APR are pretty simple too. It's exactly how you were testing it yesterday, so we're using Postman, or HDV Pi, alright you were coming in here, you were doing something like you know, http and local host to your port and you'll be like slash tigers, alright and you do like a gate request to that and you want to see what comes back.
You actually just, that's what we're going to do for the test but you visually looked at what came back you're like "Haha that worked, that's exactly what I expect it to be" You look at the headers, all that stuff that's exactly where we're going to be writing the tests it's just that we're visually not really looking at it and the test is going to be looking at this stuff. So we can use a combination of frameworks like Jasmine or Mocha, an assertion library if we don't have one. So if we use Jasmine, Jasmine has an assertion library built into it, but if you use Mocha, you have to provide your own assertion library. So we're using a combination of that stuff. And then we're going to also use something like supertest. This is a framework that's built on top of a framework. So there's this request framework for what's called "Superagent" you can think of it as like the Ajax for your server, that's pretty much what it is.
It's like the Ajax for your server, it's actually built by the same person that made Express. So this thing called Superagent, and then on top of that there's this thing called Supertest which allows us to test our application also built by the same person who made Express, that's why these two work so well together, because Supertest is made to work with Express. So that's what we're going to use, we're actually going to use Mocha, Chai, and Supertest to perform integration testing on the code that we wrote yesterday. So here's an example of what a test will look like.
So, first thing we do is we require app, and the reason we can do that is because we exported up here. This is why we exported, 'cause now we require it. So now we have our application, our server, we require Supertest, Mocha's already loaded up, and we're just going to just ride our tests. In this case, we're talking about "To-Do's" so we describe our to-do's, we make an assertion here, "It should get all to-do's", right so we made a request to our app, it's a get request. Set this URL, we're going to set some headers here, and then we're going to make some assertions right here.
So we expect the content type to pass this regex which is a jason so we expect the content type to be jason, we expect to get a two hundred back from the server, and then done, we also get to inspect this response object right here. This response object is what the server send back so we can go ahead and make assertions on that, so now I can say oh, I respect- I expect the response dot ID to be defined. So... and then done, so this is an arbitrary test.
So you can do stuff like this, you got a question Mark? - [Mark] A couple came up here, if using a testing module should we put that in our dev dependency instead of dependencies? - If using a testing module like Chai and, yeah so if you're using anything related to development or testing, yes, that should be in your dev dependencies, so the way you would do that is when you NPM install, so if you were going to NPM install something for testing you say NPM install and then you can do dash uppercase D, or you can do dash dash save dash D, or deve, And then the name of the package.
And that would save i your dev dependencies. So yeah, if it's for testing, it's definitely dev dependencies because your app actually doesn't need it to run, it's only there for testing but you don't need it to run, so you save it in dev dependencies. Good question. - [Mark] And the next one was on testing frameworks could you comment on benefits of using something like Mocha, Jasmine, versus something that gives you less for free? Like Tape? - Oh, Tape is actually pretty awesome, I just started using Tape like a month ago, but I don't know it well enough to recommend it, and I didn't really know it's benefits until I used Mocha and Jasmine for so long, but as far as like Mocha and Jasmine, Jasmine was the first one and it's like the full sweep. Jasmine is the one who's like yeah we're going to use this- we're going to write tests like this describe it, all this cool stuff, we're going to supply you with an assertion library. And then Mocha came along written by the same person who wrote Express, or I think he's more than one person to be honest, think it's a group of people with the same name, but he came along and they were like yeah we're going to write something just like Jasmine with the same syntax so it's familiar with everybody but then we're not going to require them to use all the built-in tools, we're going to let them use whatever they want.
So Mocha is just like Jasmine, except it doesn't come with an assertion library, a mocking library, and stuff like that, so you got to go get your own. So if you want the full sweep, use Jasmine, if you want to use your own third party stuff use Mocha, and as far as Tape, I prefer Tape these days it's actually my go-to now, so. - [Mark] Another one, rolled in here right at the end too when we're running the server in the workshop, the program will use all modules in both dev dependency and dependency but when in production, it only uses modules in dependency, is that right? - That's not entirely true, it depends on what environment you deploy in, so like, for instance, let's say Heroku, if you deploy to Heroku, by default Heroku will run NPM install production, so it'll only install your dependencies inside a dependency not dev dependencies. But, if you're here, and you run NPM install, it's going to install every single dependency whether it's dev dependency or a real dependency.
So, you can also tell, you can force it to install which ones too, so that's not entirely true, it depends on what platform you're going to, but you can always override those commands, but that is the reason why those two differences exist, so you can, like, figure out which ones you want to install, so, I wouldn't say that's guaranteed, but by default, yeah that might be the behaviour on some platforms like Heroku, but again you could override it. So, but yeah, we'll talk about variables and how to trigger those things in a minute.
Cool. So yeah, here's a basic test. It's doing exactly what we would do. We're going to make it get a request to this URL and we expect all this stuff to be true. Or to be whatever we make it, whatever we say here.
This course was created by Frontend Masters. It was originally released on 12/30/2015. We're pleased to host this training in our library.
- Executing Node.js
- Using Express
- What is middleware?
- Testing in Node.js
- Using Mongo with Node.js
- Data modeling
- Querying data with Mongoose
- Identifying sensitive routes
- Configuring the deployment