Know Your Bounds12:41 with Craig Dennis
Learning code boundaries will help you spot edge cases.
- Pragmatic Unit Testing in Java 8 by Jeff Langr
- hamcrest - an acronym for matchers is a more descriptive way to assert things. If you'd like to have a workshop on these, I'd be happy, just let me know you're interested in this powerful library.
- System Rules collection of testing rules for faking out System.
C - What happens when the unit receives data that doesn’t Conform to the expected format?
O - Is the Ordering of values returned in the expected order. Applications where listing results in a certain sort order is important, should definitely have tests proving that this works as intended.
R - Make sure that you check the Range. What happens if you go below the minimum or over the maximum value allowed?
R - Does this unit Reference any other code from another unit? Is that other code unit tested?
E - Remember that Existence is important in most units. Are things allowed to be null? What happens if they are?
C - You should check the different possible number of elements in a grouping, or Cardinality. Related to existence, always check what happens when there are 0. What happens with a single value, what happens with multiple values. This is often called 0-1-n, because none, one and some usually produce different expectations.
T - Remember to always take Time into account. This can be relative as well as absolute. Like for instance, sometimes applications require things to happen in a certain order. What happens if it doesn’t?
Life sure would be easy if everything always stayed on the happy 0:00 path, wouldn't it? 0:03 But we know, this isn't the case. 0:04 Part of the awesomeness of unit tests is we can plan and 0:06 check on what happens when things don't go so well. 0:09 Actually before, they don't go so well. 0:11 Now, so far, we were just kind of testing what was already in place, surrounded 0:14 around errors that I had anticipated or that techs had pointed out directly to us. 0:19 However, you can also use tests to explore how things might break and 0:24 what it looks like when it does. 0:28 So, how do you find common ways to break stuff? 0:30 Well, guess what? 0:32 I got another handy pneumonic trick that I picked up from Jeff Landers' 0:33 awesome book "Pragmatic Unit Testing". 0:37 Now, I've found that these are hard to think about all at once. 0:40 This little memory tool will help you run through them quickly. 0:43 Unfortunately, we're not going to be able to cover all of these in detail, but 0:47 we'll explore them a bit. 0:50 And I dropped a link in the Teacher's Notes, if you want more info. 0:52 Ready? 0:55 So, when you wanna think through what might go wrong around the edges of 0:56 the happy paths, these are called boundary conditions. 1:00 This is where the possible problems are usually lurking. 1:03 Try to remember the correct way to find them. 1:06 What happens when the unit receives data that doesn't 1:10 conform to the expected format? 1:13 Is the ordering of the values returned in the expected order? 1:16 Applications where listing results in a certain sort order 1:20 should definitely have tests proving that this works as intended. 1:24 Make sure you check the range. 1:28 What happens if you go below the minimum or over the maximum value allowed? 1:30 Does this unit reference any other code from another unit? 1:35 Is that other code unit tested? 1:39 Remember that existence is important in most units. 1:41 Are things allowed to be null? 1:44 What happens if they are? 1:46 You should check the different possible number of elements in a group or 1:48 cardinality. 1:51 Related to existence, always check what happens if there are zero. 1:53 What happens with a single value?, what happens with multiple values? 1:57 This is often called the zero one in, because none, one and 2:01 some usually produce different expectations. 2:05 Remember to always take time into account. 2:09 This can be relative as well as absolute. 2:12 Like for instance, sometimes applications require things happen in a certain order. 2:14 What happens if that doesn't? 2:19 Check the teachers notes for more about these. 2:20 Let's go see some of these boundary checks in action. 2:22 So, how about we write some tests for the bins? 2:25 Now, text was pretty particular about these should work. 2:28 Remember, he wants to make sure that you keep the same items in the same location. 2:31 So, let's look at the bin class. 2:36 So, it looks like, 2:38 if we restock here it looks like we have a heavy path just doing that, right? 2:39 So checks and makes sure that if it's not empty the name equals 2:42 get item name, then, it doesn't equal it, then it says it can't restock. 2:47 And it throws an IllegalArgumentException. 2:53 Let's make a test. 2:55 So, I want to do Command+Shift+T. 2:56 And it can't find one, so I'm going to create one. 2:57 Let's go ahead and leave a before in there. 3:00 And okay. 3:03 So let's go ahead and make a new bin. 3:08 Say, ten. 3:14 Right? That's how many 3:15 items can be stored in there. 3:16 So, go ahead and create a field. 3:19 Bin. 3:23 There we go. 3:24 All right. So, 3:25 let's make a test where we attempt to restock with different items. 3:26 Let's do that. 3:29 So, we'll say new test, 3:30 and we will say 3:36 restockingWithDifferentItemsIsNotAllowed. 3:38 Okay, so we will first, let's stock it up. 3:48 Let's put some delicious Cheetos in there. 3:51 Was not product placement. 3:56 And then, let's also put some delicious Doritos as well. 3:57 There. 4:04 Okay. 4:08 And let's, well obviously we know that it throws an exception, oops. 4:09 Let's make it throw that exception as well. 4:17 So, it was an IllegalArgumentException. 4:21 Cool, so let's run that, make sure that's working. 4:27 Awesome, our bin test passed. 4:30 Okay, so that was using, this Bin here was using 4:32 getItemName, which checks to make sure that things are empty. 4:38 So, we need to be careful about that right because the item, it might be empty. 4:43 So we need to make sure that every place that we use that, we need to check for 4:48 cardinality. 4:51 Remember that? 4:52 Where we check for zero, one, or more? 4:53 So, we need to make sure that anything that's looking for 4:55 information about the next item in the bin returns the right thing. 4:57 GetItemName here is totally protected, see how it checks for empty. 5:01 But why don't we check for what happens if there's no items in the bin and 5:05 we check the price. 5:10 What should happen? 5:11 Let's see. 5:13 It should return zero right? 5:14 I hope so. 5:16 I mean, I know that you can buy ghosts on Ebay, but we don't wanna be charging for 5:17 nothing, so let's add that edge case. 5:21 So, let's flip back to the test. 5:23 Let's add that edge case for what happens when it's zero. 5:25 Let's make sure. 5:29 Let me say when empty price is zero. 5:32 So, we'll just go ahead and because it's going to start out empty, so 5:38 say zero bin get it Item price. 5:42 Let's see what happens. 5:45 That should happen, right? 5:46 Testing this edge case here, oh! 5:48 We got one! 5:51 I mean, well we found one, that's not a good thing, but it's good for 5:53 what we're doing right now because we're gonna fix this, right? 5:56 So, let's go back to our bin class here, and let's take a look and 5:59 see why is it returning a null pointer exception. 6:02 Oh! 6:05 Because it's just doing a peak in the peak here is it's chain is gonna return a null, 6:06 and if you call get retail price a null, Null pointer exception. 6:11 We don't want that. 6:16 So, let's go ahead and what should we do? 6:17 It should return 0, right? 6:19 So, let's just fix the code here to make the test pass. 6:20 So, say if is empty, let's return 0, right? 6:23 We can do that, we can return 0 in the middle of a, oops. 6:28 And then, if it's not empty, obviously, 6:33 there's 1 in there it can get the retail price of what's there. 6:36 Let's go ahead and run that. 6:38 All right, our test passed, good job. 6:40 You know what? 6:42 I saw in there. 6:43 Let's make sure that this never gets broken, 6:44 that nobody thinks that this line should just go away. 6:46 So, let's go ahead and add the test for that. 6:48 Again, that's pretty easy. 6:51 New test method, and let's say 6:53 whenEmptyNameIsNull, little probably more specific. 6:57 Maybe we could word that better, but let's make a new test. 7:02 So, let's use this assertion, there's a lot of assertions on here and 7:06 we haven't really played with too many of them. 7:09 Let's do assert, no. 7:10 Oh, look at that, there's one in here for that, exactly what we want, and 7:12 it just takes the object or a message in the object like we saw, so 7:15 we'll just pass and get item name, right? 7:19 So, that should make sure that, that's pretty explanatory in what it's doing. 7:21 Bam! 7:26 Awesome. 7:27 Here we've used another assertion in the awesome assert class. 7:28 There are a ton here, and there is an even more expressive language that is outside 7:31 the scope of this class called Hamcrest, which is an anagram for matchers, 7:36 where you can match on these different things. 7:41 Check the teacher's notes below for 7:43 more info on these powerful descriptive assertions. 7:44 So, let's try the boundary check surround range. 7:47 Remember, the second R in the correct pattern. 7:50 So, range-wise, we know that there's a top limit, right? 7:53 It's ten. 7:56 I know that there should be code in place to stop overstocking. 7:57 Well, why don't we just rock out a test really quick and 8:00 see what happens when we overstock? 8:02 Because it's faster just to write the test, right? 8:07 So, let's just say over stocking not allowed, see what happens. 8:10 So, we'll do a restock delicious Fritos, I'm getting hungry, 8:17 twenty six hundred, one hundred, and fifty. 8:22 Okay, so let's run that. 8:27 Oh, that's a very descriptive error message. 8:32 It's dynamic, it says there's only 10 spots left. 8:34 That would be nice to test, wouldn't it? 8:37 Since we're taking the time to make such a dynamic message, 8:40 we want to make sure that the message actually says what we want it to. 8:42 The current way that we're testing exceptions, 8:45 we just use the expected value in the at test annotation. 8:47 Well, there's a pretty powerful tool in j unit called rules. 8:50 Let's touch on them here briefly and then, 8:55 I'll show you in the notes where to learn more about them. 8:56 So, rule allow you to redefine behavior in each test method. 8:59 There is one to do exactly what we're talking about here. 9:04 If you wanna access the exception thrown inside your test and 9:07 still ensure it's thrown, you wanna define a rule. 9:11 So, what you do is make a rule with a rule annotation just like this. 9:14 We say @Rule. 9:17 Public. 9:23 And we're looking for ExpectedException is the name of the rule. 9:25 And we're gonna name it thrown. 9:30 You can name this whatever you want. 9:31 And by default we want it always to be none, right? 9:34 We don't want the exceptions to be thrown unless we specifically say so. 9:38 So, in here, in our test, in this overstocking, we want to arrange and 9:42 we wanna say that thrown.expect, and we expect right down here, right? 9:48 Let me get that out of the way. 9:54 We expect illegal argument exception to be thrown. 9:56 Illegal argument exception class. 10:00 And then, we also want to specifically expect the message. 10:03 Expect that there are only ten spots left. 10:10 So, grab that. 10:15 Put it here. 10:16 Here we go, I'm gonna run it. 10:19 And boom, it passes. 10:23 And note that it doesn't have the expected appearance inside 10:24 here is where we're using the rule. 10:27 It's pretty powerful, right? 10:29 Now we're making sure that with the value goes out of range that we catch the error 10:31 and that the dynamic message provided is correct. 10:35 So, let's take a look again at our alpha numeric chooser test. 10:39 So, let's alpha numeric chooser test. 10:42 There we go. 10:45 Our choosing wrong input test here is a great example of a conformance test. 10:45 The C, right? 10:50 We have another range test on choosing larger than max columns is not allowed. 10:52 Hey, let's check the range of what happens when we use more rows 10:56 than there are letters in the English alphabet, which is 26 right? 10:59 So, we'll make 11:03 constructingLargerThanAlphabetNotAllowed. 11:08 So, we'll just make a new alphanumeric chooser, 27, yeah. 11:17 We'll go ahead and run that. 11:26 Ooh, maximum rows supported is 26, so again it's a dynamic message. 11:30 Why didn't we catch that? 11:35 Actually, why don't I put that on your plate to catch and 11:36 verify that we get the message correctly. 11:39 Boundaries are super helpful when your trying to find out 11:41 how your code might break and they're especially helpful when considering 11:44 when writing tests first by using test driven development. 11:48 Now, we had already done a pretty good job of thinking through 11:51 plenty of possible bugs but the boundaries will help you think through even more. 11:53 There's tons of good stuff in the teacher's notes. 11:58 Glad you got a change to play around a bit with rules, they are super powerful and 12:01 you can also write your own. 12:04 There's actually third party rules that you can use. 12:06 Someone wrote one that lets you fake out the input and 12:09 capture the output from a console based program. 12:12 Speaking of faking, one of the important pieces of test that we haven't covered yet 12:16 was mentioned in both of our acronyms. 12:20 First and correct. 12:22 The I is isolated and the second R reference. 12:24 So, how do we make sure that our tests are isolated? 12:28 The answer, my friend is test doubles. 12:31 And it's part of a larger discussion which is what should we not test. 12:34 Let's go learn about what not to test right after this break. 12:38
You need to sign up for Treehouse in order to download course files.Sign up