Creating an Open Source JavaScript Library on Github

Exercise: Writing Unit Tests

Kent C. Dodds

Kent C. Dodds

Professional Trainer
Creating an Open Source JavaScript Library on Github

Check out a free preview of the full Creating an Open Source JavaScript Library on Github course

The "Exercise: Writing Unit Tests" Lesson is part of the full, Creating an Open Source JavaScript Library on Github course featured in this preview video. Here's what you'd learn in this lesson:

In this exercise, you will write unit tests that cover the starWarsNames.all() and starWarsNames.random() methods. To start, Kent provides some pseudo-code and a few hints. He also talks a little about the dont-break NPM package that verifies changes to one project don’t break dependent projects.


Transcript from the "Exercise: Writing Unit Tests" Lesson

>> [MUSIC]

>> Kent C. Dodds: Now that we have verified that we have our tests and framework setup and stuff, let's go ahead right into test. This will be just another fun exercise. Yeah, don't forget to check out the next branch, to make sure we're all on the same page. So that is an FEM/05.0-setup-tests.

>> Kent C. Dodds: And with that, sometimes my highlighting doesn't update, but those files are there. I totally forgot to setup the watch command. So this is the watch command. It's just mocha --watch, and because we have the mocha.opts here, it's gonna point directly to our index.test file there. So, this is what I recommend while you're writing your test for libraries.

So who here is actually, before I do that, who is familiar with TDD, know what that term means? Okay, several of you. It stands for Test Driven Development. Test driven development is like, this is also yet another preferential controversy almost thing. Some people really, really like it. Some people really, really don't.

I really, really like it for libraries. I don't use it quite as much for applications. Libraries generally have a really defined set of tasks that you're trying to accomplish. They have a really well-defined API that you want to test around, whereas applications, especially UI, it's a little more fuzzy about what to test and stuff.

So doing test-driven for that is a little more difficult, though I still do it sometimes. But yeah, for libraries, test-driven development is awesome. And having a watch command like this is really valuable for test-driven development. So basically, the idea of test-driven development is you start with a failing test, then you write the code to make that test pass.

And then you repeat, and you go through that cycle. We've actually already written our entire library. I thought that would be more like, interesting for you all to do. But as you add new features to the library or, as somebody finds a bug, then what you would do is you'd fix that bug, or you wouldn't fix that bug, you'd reproduce that bug in a test.

And then, write the code to fix it, and then make sure all your other tests are still testing and then you re-factor. Sorry, I left that. They're like the three parts, red, green, re-factor. So failing, passing and re-factor so it looks nice, and it's still passing. So that's TDD in a nutshell, and so we're going to run NPM run watch:test.

>> Kent C. Dodds: And this will run our test once, and it'll just hang right there. The watch command is pretty cool, because as we make changes it will rerun our tests, and it's lickety split fast. One millisecond, that's one of the things I like about mocha is how amazingly fast it is at running our test.

So, then you can open up your test file. And this is the exercise. Let me really quickly pull out that, there are two tests that I want you to implement. And if you're not super interested in learning Mocha or learning Chai and stuff, that's totally cool, and you can just reference the solution.

But, I think this will be kind of fun for you, so that's why I'm gonna let you have an opportunity to do this. So, you need to implement two tests. So the first is should have a list of all available names.
>> Kent C. Dodds: And, this is for that all property just pro-tip.

The starWarsNames.all. So you're gonna need to require the starWarsNames module into here. So actually one of the nice things about a test is, is you're actually using your library in your test, and so you're using it as a user would use it. That's a key part of testing.

And then for this one, instead of should have all available names, it ('should allow me to get a random name from the list'. And so this one would be starWarsNames.random
>> Kent C. Dodds: So I'll go ahead and let you go off on that and I'll be available for questions. And then here in a little bit I'll start working through it, and you can follow along if you like.

But I'm available for questions right now if you have any.
>> Speaker 2: What is the watch command that you ran there in the command line?
>> Kent C. Dodds: Yeah, it is npm run watch:test, and you can find all of the available commands in the scripts property in your package json. Unfortunately, there's no shortcut to watch:test like there is for test.

So I'll give you a little pro-tip for the list of all available names. All that I really care about for this one, or you kinda had to take step back and think okay. At what point is this getting to be, over the top testing. One thing that you could do is you could say, okay let me require the list of names and it's written that those two are the same.

That's maybe one thing that you could do, but let's say that at some point somebody makes a poor request or something happens where they insert true in here. Then yeah, but that's not a starWarsName. So how can we verify that what you're getting is actually a starWarsName? And probably the best we can do, is just verify that every item in the all property is a strain.

And yeah, sure, somebody could make a poll request and say Boo, but watch your polar requests I guess. Yeah, there's only so much you can do with unit testing. For the other one, all that I really care about is whatever I'm getting back from random, is within the starWarsNames.all array.

>> Kent C. Dodds: So call in to random, get a random Star Wars name, and then I'll verify that string is contained in the all property. So, a couple of tips there. And here in a second I'll start going through it, but give you a chance to get ahead of me.

>> Kent C. Dodds: Okay, just saw Denartey's question. How to decide what should be tested. I kind of talked about that just a second ago, but when we get into code coverage then that will help you know what parts of your code aren't tested. So what functions you're maybe missing or something, and that can be helpful to guide you in what you test.

>> Kent C. Dodds: I was going to talk about this more the code coverage but, when you're building a library especially a small library like this, getting 100% code coverage is pretty easy and you should probably do it. There's not really a reason to not do that, especially with the library that's gonna be potentially used by a lot of people.

You want to make sure that every line of code can be run successfully. With some current state. Good coverage doesn't tell you all of these story, but it tells you ways that you can run the code which is valuable. In applications, I say like around 70% is pretty good code, it's like actually stellar code coverage.

I think it's kind of a mistake to do 100% code coverage on an application. Because you end up wasting a lot of time. And refactoring becomes a real pain, because all of your test break and those test weren't actually really solving. Often, you wind up testing implementation details when you're doing stuff like that.

Do more end-to-end and integration testing with that applications. But yeah, and actually integration testing with libraries is also valuable. We're not gonna talk about it in this workshop today, but if you have a CLI or something have like testing that CLI in a actual environment is valuable. Or even, there are tools that you can use to ensure that changes to your library, don't break people who are using your library.

You can look up npm.imdont-break. This is a really fantastic tool for that. That you just run on CLI and you say, hey, I don't wanna break this person or this other package that's using my library. And so, it will actually Install that and run or it'll gitclone that package, and add your changes to that package's null modules, and run that package's test, to make sure that your changes won't break that package's test.

It's pretty super. So, that's one way to do some integration testing as well, and it's totally automated and awesome.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now