Check out a free preview of the full Testing Fundamentals course
The "Testing Guidelines" Lesson is part of the full, Testing Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:
Steve walks through some general guidelines for writing tests. Tests can be easy to write. The more difficult challenge is thinking through the edge cases that must also be tested. For example, what if two strings are passed to the add() function?
Transcript from the "Testing Guidelines" Lesson
[00:00:00]
>> Steve Kinney: One thing I kinda wanna talk about real quick, is just those general principles of testing, and then we'll kinda jump back into this code. Coz now we've got some tests under our belt, and we've got some sense around it, right? As we saw, I think I've at least proven a little bit.
[00:00:17]
I got more work to do on this. I'm proven a little bit of the first one here is that the writing test isn't all that hard. You just wrote four tests, that wasn't that hard. I'm hiding some complexity from you, of course, but the actual writing of the test, not that bad.
[00:00:32]
You took two and two, you expected it to be four., it passed, great. So clearly, writing tests can't be all that hard.
>> Steve Kinney: Those test paths, we talked about that. If I was using this code, it would pass. And then breaking stuff out into those too many small, no one's ever broken their code to too many small, well-named, easy to test functions, right?
[00:00:54]
A lot of times you have two numbers just in your code or maybe you're doing a whole bunch of stuff and it's just one line in a 700 line conditional, that's hard to test then, right? And so what you can start to do is pull stuff out into these very simple functions, like our add or multiply, or it might be maybe we needed to title case the heading when we rendered it.
[00:01:15]
And maybe that's just a line of like a regex or something in a large reactor. Component to begin to pull those things out into very simple functions that have arguments and give you return values you begin to pull those pieces out, right? And maybe you can't write tests for the whole thing all at once, we take more of these small pieces and you use them as we go along.
[00:01:35]
But there's these tests leave a lot to be desired. And because they leave a lot to be desired, they do make one of my other points. Which is, if I was to run a code coverage analysis tool on this, which is basically all a code coverage analysis tool does is it starts with your test.
[00:01:54]
So code that you don't test isn't counted in the coverage report. It's only files that are imported by your test that's one way to get to 100%. Two is if we look at these tests, right? If we just did our own like mental code coverage report, you look at these tests, you look at this code, we would get 100% code coverage right?
[00:02:16]
We would everything would be great. And life would go on and we feel really good about everything. That said, there are some problems here that we have not just not thought about at all, right? What are you talking about? I added two and two, everything's great. We said that if you add two and two, everything should be really great.
[00:02:36]
And one of the things, both the mix of our testing and the way we write code, kind of interplay with each other is thinking about what we call the unhappy path, right? Which is the outside world is real problematic, all sorts of stuff can happen, right? And especially in JavaScript we know there's jokes.
[00:03:02]
Python engineers make jokes about how math works in JavaScript, and I have considered none of that in my tests, right? True plus true equals two, one plus one as a string equals 11, right? But try to subtract one as a string, so on and so forth. What happens if I happen to give you both arguments, right?
[00:03:22]
A and B, that everything works, what happens if I only give you one, right? There, no TypeScript here, right? Even then you can get around anything you use one, any, and then the world's your oyster again. And so when we think about the unhappy path, this is way to both think about our code and also think about our tests.
[00:03:37]
And then using our test and that test driven development that we saw before to get us to handling all those things, right? And again, it will repeatedly try all these things over and over and over again, right? So I said, there's all sorts of fun things in JavaScript.
[00:03:52]
Who doesn't love, not a number, right? And all sorts of ways that even our humble addition function can go horribly wrong, right? What happens if I only give it one argument? What happens if I give it null as the first argument? What happens if I give it a string and a number?
[00:04:12]
What happens if I give it the word potato, right? So on and so forth. What happens if I try to divide by 0?
>> Speaker 2: How do you pick? When we're writing tests, we decided which number should we divide? I don't know, 10, 6. Is that related to this?
[00:04:26]
Picking your test conditions?
>> Steve Kinney: Exactly, right? And so step one is we thought about that initial. Again, for adding two numbers, fine, right? This is the thing where there's no method in your test library, yes and no. But generally speaking, there's no method in your code. This involves that kind of intellectual exercise when it comes down to testing your code, right?
[00:04:50]
That is less about, well, what method comes from the testing library to help me do this? It's more about, have I over the years cultivated enough paranoia, right? Of all the things that can go wrong, right? When I talk to the junior engineers on my team and I solve a problem like this for them, you're so smart.
[00:05:09]
And I take that compliment, I marinate it a little bit, but it's not true. I've just seen more. I've burned a week on the bug four times in the last. A few years, and so now I walk in knowing looking like I know everything that's possible to know.
[00:05:25]
So we have all these cases and there is not a necessarily a right answer for all of these things, right? So we basically have three choices about how to handle these cases. One is we can figure a way to fail gracefully, right? And some of it is just a decision, right?
[00:05:45]
And you will find out in fun ways about how your decision was wrong later, right? No matter what decision you make, you will not to get Kierkegaard on you, but you will find out ways that that doesn't work later, right? And the next part is you will have those tests in place so that if you make a change to your code, you will know that things work as you expect, right?
[00:06:07]
So you get three options fail gracefully. And that means maybe if they pass us the string of one, right? You're like, who would do that? You get it from a query pram, it's a string. You didn't expect it be a string or an input field, or whatever. Lots of ways strings get in your maths, right?
[00:06:24]
You could choose to try to parse it into a number, right? You could, if they don't give you a second argument, you can just assume that it's zero. It doesn't, there's no right answer for this. It all depends on like the situation you're trying to solve, but figure out some way that the function still works, right?
[00:06:41]
Failing that, right, you could choose to throw an error, right? Especially if it's something that's gonna happen at build time or something along those are some where you have the error handling in place. Sometimes being, I don't know what to do is better than letting stuff get into a weird state, right?
[00:06:59]
The only wrong answer here is, right. Right now, if someone passed in undefined, we have 100% test coverage, and I don't know what happens on a given argument, right? So that's where this becomes again, that practice of going in here and saying and you start with what you would like the world to be like.
[00:07:28]
We might even start out with other good test cases just to make sure that they work. Coz again, the value of this test suite is it is going to hammer at my code with all sorts of different possibilities, right? So we can even start with other good cases.
[00:07:44]
It should add two negative numbers.
>> Steve Kinney: Right.
>> Steve Kinney: That should be fine. Unless you write the arrow function outside of the parentheses and then it's not fine.
>> Steve Kinney: There we go, and extra parenthesis down there. So we can expect, add negative two and negative two to be negative four, and that should work.
[00:08:18]
But also, if It didn't work in a larger case that that's good to know, right? You start to make all those assumptions about how your code should work.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops