Transcript from the "Assert" Lesson
>> Today we're going to be doing testing in node and the browser. Node already has a built in thing called assert it's part of core, so you don't even have to NPM install anything. This is, if you don't even want to install any libraries, this is a perfectly valid way to test.
[00:00:18] So why don't we just look and see how that works? So when you require the assert package in NPM, here I'm just in the node REPL. If you type node, you can get into this. If you get stuck in this, you can type Ctrl+D and you'll get back out again, just in case that happens.
[00:00:36] So if we require assert, you can see all of the methods that we have on the assert object. Actually in the REPL, you don't even have to require the core modules. They're just available. So we've got all of these ways of doing assertions. So the main idea with assertions is that these are things that you wanna test.
[00:00:57] So, for example, if you wanna test that two things are equal, you can use assert.equal. So I can show you what that will look like. assert.equal(1,1) doesn't do anything, which is just as well but what happens when those are not equal? Well, then we get an exception and the error message also tells us a little bit of information about how that works.
[00:01:25] So there's also assert.ok. So, if you pass in anything that's true or truthy, so anything that's not a zero or an empty string or false. But if you do pass in something that's falsie, you get an exception. So there's also different ways to negate those kinds of assertions.
[00:01:48] So we could do things like notOk, or I guess, notEqual, for example. So if we do notEqual, then if we do pass in two values that are equal, we get an exception.
>> Question, what is this unit test library?
>> This library is called assert. So it's part of node core.
[00:02:12] And assert is very simple. All that it does is it throws exceptions when the arguments that you give it don't match or do match, depending on which assertion method you're using. Yeah, if you type in node then you'll get the node REPL-
>> And then require assert.
>> Yeah. You don't even have to require assert, you can just type assert. In a normal program though you would have to require assert, so it's kind of a good habit to do var assert = require('assert'). So normally in your node program, you would type something like this line, right here.
[00:02:50] And then that would give you the assert library and you can poke around with that. So let's go ahead and make a library. Make a make a little test suite, just with the assert package, just to give you an idea for what the strength of the SPR chart and also what some of its failure modes can be.
[00:03:08] So we're going to write a little program that's gonna run a node. So I'm going to use some things like the fs package, things of that sort. So we'll call this test js. We can require the assert package. And then we can do assert.equal(1+2). Maybe we also have, like we have a special function here that's gonna read from a file and tell us the number of lines.
[00:03:37] So I'm gonna have a test file here. I'll just call it file.txt cuz I'm not feeling particularly imaginative. It's gonna have three lines. So here, this is just a program on the command line to count the number of lines in a file, so it should be three. I'm gonna have a little function that's going to do the same thing.
[00:03:55] And just want to make sure that my function works the way that that command on the command line works. So I'm gonna call this function countlines, gonna load the fs package, and I'm gonna read in a file. So fs.readFile('file.txt'. If there's an error, I really ought to do something about it.
[00:04:20] So I'm gonna have a callback that I'm gonna pass in. This will just kind of give you an idea for how this function works. If there's an error, I need to call that callback. Otherwise, I need to do, there's another parameter we can pass so that we get a string.
[00:04:38] So I'm going to split on new line. And then I'm going to call the length. So that's going to be, you don't really have to understand completely how this works, but the basic idea is that it's gonna count the number of lines in that file and give us the result.
[00:04:56] So maybe I messed up the implementation, like maybe I'm gonna sabotage this right now just to prove something. So what if, for example, you know what? So if I split on length, that's one way of doing it. I could also just count the number of newline characters, which is another way that would I don't think work, but I'm just gonna add 100 to, this would be an example of a mistake [LAUGH].
[00:05:22] In this case, it was intentional, but oftentimes it's not. So if I call my countlines function, I know that that File('file.txt' has 3 lines in it, so I can pass in a callback and I should get back either an error as the first argument. This is sort of just a Node.js convention.
[00:05:44] So if I have an error, I really want to throw an exception with the assert module. assert has something baked in called assert.ifError. And you can pass it, the error object, if there is one. If there's no error object that you pass in, then that function will just succeed and go on to the next thing.
[00:06:06] So the other thing that I wanna do is I wanna test an equality. I wanna make sure that the number of lines that I get back from that implementation is equal to what I expect. So in this case, it's three because there ought to be three lines in that file, except it's been sabotaged.
[00:06:22] So this ought not to work. So now, if I run this program, I see 3 == undefined. So that's even a different error. I guess I already had an error. That's good. So, our test suite in this case is telling us that there's a problem with this implementation, which is fantastic.
[00:06:43] So happens to be on line four. Right. So my first assert that I did, 1+2, I didn't actually specify the second thing that I wanted to test. So it's another thing to be careful of when you write tests is you wanna make sure that your test also doesn't have bugs.
[00:07:02] It's bad enough if your implementation has bugs. But if your test suite is also buggy, then that's gonna be even more difficult. You'd have to write another test, so test your tests. [LAUGH] I wouldn't go that far overboard, all though I do know people who do that kind of thing sometimes.
[00:07:19] So here we are. I fixed that error, can run the test again. Here we go. Now we're getting a different error 104 == 3. Notice how I added 100? So I was expecting something like 103, so I guess my program already had a bug. That's useful. I didn't even have to add one.
[00:07:41] This is how it goes with testing, often times. So if that's the case, why is that the case?
>> Need a line break after the last line?
>> Yep. So if I actually do a quick read file test on the command line, so I'm just gonna use the sync version, all though I want the implementation to be asynchronous because I'm gonna show something.
[00:08:01] Okay, so here's that file. There's one, two, and three. If you split on new line, and there's a bit of extra fluff at the end that's an empty string. So, what we wanna do is if there is an empty string at the end, we wanna just cut it off.
[00:08:17] So there's a function on strings called trim that should get rid of that extra bit at the end. So now if we run our test, our non-sabotaged test, we still get an error because that's not a property on arrays, it's a property on strings. So here we go.
[00:08:39] I've now hopefully fixed this test. I can close that. And I fixed it. You might notice that we get no output, so that's not really very helpful. Node is gonna set the exit code to 0, so that's a little bit of a help but you might notice how this kind of test suite could go wrong.
[00:09:04] Like, what if I forgot to call a callback? It would exit and it wouldn't say anything and it would just kinda look identical to a successful case. So if I do that, if I just forgot to actually call the callback or I called it twice or something, I would get the same kind of output.
[00:09:22] Which is just to exit and to exit successfully without failing, without raising an exception. So, that's kind of some of the problems also, yeah, question.
>> What's the dollar sign you had in there, where did that come from?
>> This is just something that's available on the command line.
[00:09:41] It's the exit code.
>> Okay. Yeah. I'll talk a little bit more about exit codes when we get into the section about setting scripts and package JSON. So, a little bit anyways, but this is basically how things like NPM tests or if you set up continuous integration, this is like the lowest common denominator for those systems to know when your tests succeeded or when other system scripts succeeded or not.
[00:10:07] I can show you an example of, if I put one of these errors back like I make that four, and I run the test, now the execute code is 1, so it's not 0. Anything that's not 0 is a failure case. Okay, so hopefully that gives you kind of an idea of how, yeah, this is a very simple way to do things.
[00:10:28] All though, it's kind of riddled with problems if you're not very careful and you can accidentally have cases where callbacks aren't being called and this sort of thing. Also, exceptions are gonna halt your program. So, if you just kind of wanna get a general sense for, well, you know, I have 20,000 tests and maybe 5 of them are failing but maybe they're kinda in the beginning, so I don't want my tests to stop there.
[00:10:58] I want them to like keep going anyways, even though there's some failures. That's not something that you're gonna get with the assert module. However, I think that the general set of methods that you get with the assert package are pretty handy. So we've got things like ok, equal, deepEqual, those are reasonable ways to do these kind of assertions.