 I've been a maintainer of MoCA since mid-2014. I work at IBM as a developer advocate in the IoT and emerging technology area. I'm Bone Skull on GitHub and Twitter, except with a zero on Twitter. I'm going to talk today, this is just an introduction to unit testing Node.js apps with MoCA. This is really kind of low level, I kind of wrote it with, you know, having someone who's never really done this before in mind, and so, yeah, I'm just going to kind of run through some fundamentals of testing, just a couple concepts, just, I'll keep it really short because there's a lot of concepts, but just, I'm just going to do a couple. Then we'll talk about how to write a unit test with MoCA, I'll show you that process and then we'll move on to an integration test with MoCA as well. And if there's questions about anything along the way, just pipe up and stop me. So what is MoCA? MoCA is a testing framework. So a testing framework has a few responsibilities, one of those responsibilities is providing an API to help you write tests, automated tests against your software, a test framework will also help you organize those tests. Some test frameworks, more than others, will actually let you run the tests too, and MoCA is one of those, and also another responsibility is they report the results of the tests. So you write them, and you run them, and at the end you get, you know, in various human or machine-readable formats, you know, this is what happened with the tests, these are the ones that failed, and this is why, et cetera, et cetera. So MoCA runs in Node.js, of course, and that's what I'm going to talk about, I'm not going to talk about testing in the browser with MoCA because MoCA also runs in the browser. It runs in right now. The oldest browser we support is IE9, but I think we're going to ditch that soon, then the oldest one will be IE11. Hopefully you don't need to, actually we've never tested Opera, I have no idea, I just pulled that off. Anyway, so what's cool about MoCA? MoCA is simple, it's got a very small API surface. It's easy to learn. There's really just not a lot you have to remember when working with MoCA. It kind of does one job, and it seems to do it well. It lets you write your tests, and it kind of wants to get out of the way, and because of that, it's actually, it's very versatile. So it will kind of bend how you want to, you know, how you want to push it. It's not limited to simply one kind of test. You can write many different kinds of tests, you can run that test in many different environments. You can use reporters designed for Node.js, running in a headless browser and still output like weird stuff to the console, and there are things I never consider that people use this for, and of course they file bugs about all this weird stuff. So one of the things about MoCA is that the entire user-facing API, the thing that you interact with as a developer writing your tests, the whole thing can be swapped out. There's a default, which is this kind of RSpec style API, but it can also, MoCA also ships with, if you're more comfortable with the way QUnit works, which is, I think originally QUnit was written to test jQuery itself. If you're familiar with that, you can write your MoCA tests in QUnit format, or there's several different ways you can do it. And if you don't like any of them, you can even write your own and just use it. I haven't seen too many of that, too many of those. The defaults work pretty well for a lot of people. MoCA is also, I daresay, fun for a testing framework, I suppose, because there's really no other testing framework that has a Nyancat reporter that I know of anyway. So now I'm going to talk a little bit about some fundamentals. So this is kind of, this is what MoCA is, and now we're going to go into fundamentals of testing. And so this is just going to be like three, this is terminology, this is not, we're not going to go very deep, it won't hurt, I promise. The first thing is the assertion. And so what is an assertion? It's a, fundamentally it's a comparison. And if the comparison is true or truthy, nothing happens. If the comparison is false or falsely, then it throws an exception. And it's really trivial to write your own assertion function. And here's an example. So you pass assert and a value, if that value evaluates to falsely, throw an error. That's basically what an assertion is. Testing, you're going to make a lot of assertions in your tests, that's kind of the idea. So the next term is the unit test. And so a unit test, it's kind of like this recursive acronym or not. The definition is, well, it's a test of a unit and that doesn't mean anything, right? You have to know what a unit is. And so a unit test asserts a unit behaves as intended. So a unit is the smallest testable chunk of code. So generally that's going to be a function because you can't very easily crawl inside a function and pull a little bit out and just test that piece. So we're talking about functions most of the time, but not always. You can have a unit test that maybe is testing events or something like that, where it's not a function itself that you're testing, per se. So a unit test then has two responsibilities, one, it executes the unit. And so I may refer to this as the unit under test or code under test. The unit test then makes an assertion about whatever it just did. And so in the case of a function that returns something, like say you have a function and it adds two numbers, that is your unit, call it, call it add or something, and you pass it two and two, your unit test is going to execute that function and then it's going to make an assertion that the function returned four. So that's one way. If your unit just does some side effects, and we'll see that here in a minute, like maybe it modifies some application state, your unit test is going to execute your function and then it's going to make an assertion about the state of the application. Here's the last concept, there are only three I'm going to do. So it's the integration test. And so I found when I started writing unit tests, I would not really be sure what I was doing or in some cases the code I was trying to test was just very poor and coupled too tightly and I was trying to write unit tests. In fact, that's what I thought I was doing, but I was writing integration tests. And so an integration test asserts like a, it's a test across multiple units or multiple modules, multiple layers of your application or multiple subsystems. When your unit test starts testing other units too, you just wrote an integration test and you can get really confused and your whole tests, all your tests can get really confused, but if you find your unit self doing that all the time, it might be a sign that it's not the test that's the problem. It's that your code's not very testable. So an integration test is a test across groups or layers. And if that sounds vague, it's because it is vague. It depends on your software's, the kind of application you have. Maybe a web server will have an integration test between something that's going to hit a JSON endpoint or something. Maybe a command line app is going to have something different. A desktop app, whatever an integration test is really just depends on what you're trying to test. You may not know how, I feel like this is, this is like required to put in a tutorial like this. This is how you install Mocha with NPM, how you install most things. I recommend you use, save it as a development dependency with, I like capital D. Some people like save dev, but whatever. So this is how you install Mocha in Node. If you're going to use it in the browser, it's a different story, maybe. So never mind that. I'm just talking about Node. This is how you do it in Node. And so what happens when you do this? Well, Mocha is added to your manifest, which is package.json. It's in the dev dependencies property. It becomes part of that, you know, that object. And it also gives you the Mocha executable, which lives in your local Node modules in the .bin folder. I have no idea what that looks like on Windows. All of this is going to be, you know, Linuxy, Unixy type stuff. I'm not sure exactly how that works on Windows, but. So you get a Mocha executable. It's in your manifest and next time you're on NPM install, you'll get Mocha, so great. But if we're installing Mocha, that means we have something to test. And so this is what we have to test. So this is the obligatory contrived example, which is some Express middleware. I couldn't think of, I mean, I don't know what else to do. It's something that's kind of practical, but really, really simple. So if you're unfamiliar with Express, Express is like the defaults, like Web server framework for Node.js. It's what you're probably going to reach for. There are other ones, but most people just use Express, it seems. And so Express is kind of this wrapper around nodes built in HTTP server, and it basically functions as like a list of, it's built out of these things called middleware. And so middleware is just a function, this is middleware. This function accepts three parameters. When you build an Express app, you basically chain all these things together. You set up routes, and what happens when a request comes into your server is that request gets filtered or sent through all this different middleware, and eventually something happens and you get your response. And so a middleware function accepts a request, which is REQ, which is this object that represents the request, whether that's a get request, a post request, somebody use some machine hitting your Web server. And the response object, which is going to be this thing you're building, and that's what you're eventually going to return and send it back to the requester. And then there's this third parameter to middleware, which is next, and it's a function, and it says, I'm done doing what I'm doing, go ahead and execute the next middleware, whatever that is. You don't really care what it is, it's just like, it's like a queue and it knocks off the next one. And so this particular bit of middleware, it adds a request time property to the request object, and so it's not a, it's a JavaScript time stamp, which is not a Unix time stamp because it's in milliseconds. Anyway, that's what it does, and that's all it does. And so we decided we wanted to write a unit test for this. And so we're going to make one. Mocha will, it has some defaults, which I think are pretty reasonable. If you make a folder called test, Mocha assumes that if you give it no other information, it assumes your test files are in there. And so if you make a test directory and put a file in it with a .js extension, it will find that file and execute it. By convention, we like to name these files with the .spec.js. I don't know where that came from, but it's just one of those things. Well, we always did it that way, so that's kind of how we're doing it. But it's a good way to say, you know, just visually tell, oh, this is a test and not a source file. Some people like to put them next to the source files, which is another way to do it. But anyway, by default, it looks in this test directory. And the file we're going to create is request-time.spec.js, which will contain unit tests for this middleware. And before I go any further, and this is something that people get really religious about, it's that Mocha uses globals. When you go and you want to write a test that Mocha is going to run, you don't have a require Mocha, like give me all these functions at the top of your test file. You don't have import stuff from Mocha. Mocha doesn't even use a namespace. It doesn't even have that sort of courtesy. It simply just dumps everything into the global namespace. And the browser that's going to be the window object and node, it's the global object. And so why? The only reason that I can think of it, now I didn't write Mocha, I just maintain it. But I can only speculate why some of the decisions were made. But it reduces boilerplate, plain and simple. It's a trade-off, a design decision that was made, because you know what, I don't want to have to require all this crap at the top of every file, because I got 400 test files. If we simply throw things into the global, like you're not supposed to do that, but we did it anyway, and so there it is. It's for developer ergonomics, more or less. It reduces boilerplate, and some people don't like this. But it is what it is. What we want to do is create a suite. And so what's a suite? It's a way to organize your tests. So a suite will contain tests, it will contain something called hooks that I'm not going to talk about. But you can also put other suites in them. We use a function called describe to create a suite. And you give it a title and a callback function. And the callback is the body of the suite. And so the title is, you know, this is a logical organization. Whatever makes sense to you, you can nest the hell out of these things or not. It's up to you. But since we're going to write a test for the request time middleware, that's what we're calling a suite. Estimulatively, we would have more than one, but in this talk, we do not. And so next, we're going to start trying to turn the right unit test. But another kind of gotcha about Mocha is that it doesn't actually contain anything to, oops. But so the question was kind of about conventions for naming suites, naming tests. And so, you know, I feel like some people who really are into this, the whole BDD thing, which I'm not going to go into, you can look it up, it's behavior driven development. It's more than just like, it's more than just coding, you know, it's like a whole like business process thing. And if you're really into that, I'm sure they have some really nice rules that you get to adhere to. But I'm not one of those people, and I don't think most people do that. And so I think at some level, it doesn't matter too much. What I like to do personally is I will have like a suite and it will kind of give a basic description of where we're at. If I have some sort of condition, I might want, and within that condition, I need to have multiple tests. I like to have one assertion per test. And so if I have a suite with some condition, and then I'll have some tests in there, and then I will like try to chain them with and and say, so, you know, we'd start with describe request time middleware, describe when such and such is true, and then we're going to have another describe, and such and such is false. It should blah, blah, blah, blah, blah. And so I try to make it kind of like a sentence, but I don't go crazy about it. I mean, there's things, I mean, if you have a test, this, you know, like TypeScript, I think is the biggest consumer of Mocha that I know of. They have like thousands and thousands of tests. Maybe you should ask them how they do it, because like I can't imagine now to organize something like that. But you know, I think just whatever works for you is fine. There's no reason in my mind to, you know, some people like to have like special tokens in there so they can grep for things and stuff, and I don't know. But so, and you'll see that there's, I talk a little bit about this kind of English language type thing. But so Mocha doesn't have any functionality in it to make assertions, which is odd for a test framework. It seems like kind of a fundamental part of a test framework, right? So with other test frameworks, like maybe Jasmine, you get the whole enchilada. And like Jasmine is really similar to Mocha. You just, you get everything with Jasmine. You get your spies, your stubs, your assertion framework, blah, blah, blah, blah, blah. You get everything in there. But Mocha doesn't, and again, I don't know why one can speculate. Maybe the original author felt that it was simply, you know, the best way to give people the flexibility to work the way they want. Maybe he was lazy and didn't want to do it. I don't know. But I could look at this problem now with hindsight and say, you know, he made the right choice because, you know, after he wrote Mocha and it started to take off, it started this kind of, you know, a market or it's just like, you know, all these little assertion libraries started popping up. And now there's quite a few and they're all different. And so people have found lots of different ways that they want to write assertions. And certainly now, Mocha couldn't support all these, you know. It's kind of like unexpected and in CHI, and CHI especially is an assertion library that has its own ecosystem. I mean, it's, there's just like a ton that you can do. And I think originally the right choice was made not to kind of go there with the assertion library. But Node comes with one. There's an assert module. Node uses this assert module to test itself. And we're also going to need our middleware. And so this is our unit test file. And we're just going to pull in the assert module. We're going to pull in our middleware. And next we're going to create a test. And so before we had described for a suite and then in the suite body, we put a test and you create a test with it, title, callback, very similar. You can see here, it kind of went out a little bit. But so putting this more together, so we have request time middleware. It should add a request time property to the REC parameter, which is basically all that little middleware function is doing. And so here we have a call function, make assertion, most notes. This is what's going to go in there. And it's, if you kind of write your tests like a sentence, can you know that? Then the reporting will look a little nicer. So here we go. Here is my first try at the unit test. And so my unit test is going to call request time. It's going to pass a empty object. And why is it going to pass an empty object? Well, this middleware function, when you're writing your test, you have to think of that unit as a completely standalone piece of code. It shouldn't be coupled to anything else, really. And the middleware, as you wrote it, it doesn't know anything about express. All it knows is it gets three parameters and adds a property to some object. And so the object that it adds a property to might as well just be an empty object. And this is an example of a unit that just basically has side effects. It doesn't return anything. So we have this, we call request time. And so now the state should be modified. And we can make an assert. And so make an assertion. So assert okay. Okay is maybe it's the same thing as the assert function. I don't know. But basically you pass something to okay. And if that something is truthy, then it passes. If not, it's false. Very, very simple. Just pretty much the same kind of bare bones assertion function you wrote before. And so if you know what's going to happen here, don't spoil the surprise. It's good surprise. I promise. Now we're going to run this. And so how do we run it? We, it ends up in node modules. And so we just call mocha. It looks in a test folder. It runs all the files in that test folder. And it fails because why? So what do we see here? We see this first line request time of the where. This is the suite. Below that is a test. And I believe that, yeah, that number shows up to cross reference down here. It's a number if it fails. It's a check if it passes. And we can see we have no passing tests in seven milliseconds or one failing test in seven milliseconds. And what happened? So it gives us the suite again that failed. It gives us the test title that failed. And right after that, it gives us a stack trace. And then the stack trace goes on a while. I cut it off there. But the important part is next is not a function. And so why is next not a function? It's because our middleware tries to call a function called next. And we didn't give it one. Oops. So let's take a look at that request time source again. Okay. So what can we do? We could do it like this. So we have that empty object again. And the second parameter, it needs a second parameter. We don't use a second parameter for anything. But it needs something in there, right? So null could be void zero. It could be anything. It could be foo if you want. It doesn't use it. Doesn't matter. But the third parameter is a function. It simply calls a function. And so it has to be a function. That function doesn't have to do anything. And so then we assert that the request time property is greater than zero and run it again. And great. It passed. So does anybody have any questions about this kind of this flow of writing unit tests and executing mocha? And yes. Or it's stubbing. I would call it a stub. Yeah. And so you're going to find yourself creating something called stubs when you're writing unit tests quite often where you have some dummy data or maybe that unit calls another function somewhere. And maybe you need to stub that out because you don't really care what that does or you want to say, oh, so I have function A that calls function B. Well, what happens when function B, what happens to function A when function B returns such and such? You have the stub or this, that basically pretends its function B and returns a certain value and that's kind of up to you. And so there's a lot of kind of bickering about what's best there. And I think it more comes down to not how your tests are written more importantly how your actual code is written. But your test can be indicative that your code is not good. And so this pass, that's great. We have an integration test example. And so again an integration test is it's like it's the next level up from a unit test. It's like you pull back and you get this higher level view. It's as far as we're going to go with this one. But so what do we have? You're looking at like an express-based web server here. And so all this thing is doing is it creates an express server. It pulls in our middleware and then it registers a root. That's this app.get. And so when I start this server on port 3000, and if I go to the path, if I go to localhost colon 3000, forward slash unix-timestamp, it's going to execute this code. And so what this res.json thing does is it sticks a JSON response in the JSON object in the response built from my object here. And remember if I mentioned that a JavaScript timestamp is not a Unix timestamp, but we want a Unix timestamp. And so we need to turn that into seconds. And that's about as good as we're going to get there. And finally this bit at the bottom, I don't know. Some of you may have seen something like this before. But basically what you can do with this file is you can either require it or you can execute it straight away. So you can say node app.js, and then it'll start listening on port 3000. But if you require it from some other module, it will not listen because that's not the main module. It's just kind of an easy way and maybe not the best way, but it's a way to get at this application that we've created and test it from an integration testing standpoint. And one thing with integration testing, and as you get kind of to a higher and higher level when you're testing your code, we should go to integration tests or finally you end up with end-to-end tests where you're hitting a browser maybe and clicking some buttons and it tests all the way through to the data layer. The higher up you get, the more tooling you need. And so here we are at integration tests and this would really be a pain in the ass to test without some nice helpers. And so there's a great helper called Supertest. And Supertest is a, it's basically, it's like a mutant assertion framework that helps you test express servers. And you're going to need to express too, but Supertest. So basically it runs these requests against a server object. You don't have to start a server in process A and then tab over and then start your tests and start hitting the endpoint. You just give it the server object and you can work with it directly, which is kind of nice. You don't have to listen on a port. Apparently it's a lot quicker. I haven't used it too much, but here it is. So Supertest. And so we have our assert as before. We have our app. And so this was that thing I just showed you which is this dude, this is app.js. And so we pull that in and we have our sweet getUnix timestamp. So all the stuff that we want to test when that endpoint is hit with a get request. We might have multiple tests in here, but we just have one and our test should respond with JSON object containing timestamp. And so this is the same type of thing that we're asserting before, but we're asserting it at a higher level now. We want to make sure that, you know, not only was request time written properly, not only does that function do what we thought it should do, but our whole system works. And the point of our system is to have an endpoint with returning to Unix timestamp. And without this integration test, how can we be sure other than the test manually? Because our unit test won't tell us if our app actually works. And this won't really tell us that, but it'll get us closer. So there's a couple of ways to do it. One is this node back style with callbacks. And this is an example of a asynchronous mocha test. And so when you're using super tests, you're making HTTP requests in tests. These are asynchronous. In this case, so it's kind of magic in mocha. So you give it this done function. And if that done function exists, mocha will expect you to call it. It doesn't care when. It will eventually time out after so long. But it wants you to call done at some point. And so you can do all sorts of async stuff in here. And then when you're finished, you call done. And so super test is this request function. And we pass it our app instance that we had before. Dot get would be pretend I'm a get request to the Unix timestamp path of this server. We expect, and this is kind of the assertion portion, we expect a 200 okay status back. And then finally, when we're done, if there's an error, which I don't think there really could be an error here, but if there is, we can hand that back to done. And so this is the kind of error first callback thing that was so popular and still is for some people. But finally, if that's okay, we can make our assertion again. And so what I did there was, now that I've divided this millisecond style timestamp by 1000, I can now be sure that it's a Unix style timestamp, maybe if it's under this very large number. If I didn't do that division, this would fail. Anyway, so that's one way to do it, but that way sucks. So this way is even better. And you can probably get even better too with async await. But with Mocha, you can simply return a promise. And if you return a promise from a test, it says, oh, you're in async test. Okay, great. And so this just works with promises. It's the same exact test as before. So we checked to make sure we got a 200 okay. And then we look at the response in that body, which has been like, magically becomes a JavaScript object out of its JSON format. We checked the timestamp. And so, there we go. And so we just run Mocha. It finds that we just added this other, I can't remember what I called this file, but we tossed it in there and into the tester. And it just ran both of them. So the question was, do if you have an asynchronous test, is it reported asynchronously or is it reported in order? The answer is it reported in order. Mocha, it only works in serial. It will not execute two tests at a time. If it's doing something like that, you're probably gonna get a really hard to debug error. And you're doing something wrong. But yeah, it just runs, it's gonna run Unix timestamp and it's gonna hang out there and wait until that's done before it goes to this other file. It's yeah, it runs everything in order and it will not try to do two things at once. That's about all I got. So before this, Ben said I was super positive, which is really weird. And so, but I don't wanna let him down. There you go. That's all folks, balloons and a moji and a poop. And these slides and the example code is up there at this URL. And you can download it and install it and run it and stuff. All that code is an example folder and it works, I think. So.