What Not To Test9:37 with Craig Dennis
It's super important to also know what you shouldn't test, and what you should stub out. Let's explore!
There are things that we shouldn't test and 0:00 if we follow the best practices that we've picked up thus far 0:02 we'll probably not end up falling into some common pitfalls. 0:06 You wanna make sure that you don't test stuff that can't really break. 0:10 A good example of this is testing of getters and setters. 0:13 In a behavior to find test you probably won't even think of this, but for 0:18 those test that's simply test all the methods, 0:21 you might actually encounter someone testing a method like test get name. 0:24 That's pretty silly right? 0:28 I mean, how could that actually break? 0:30 Especially if it's just exposing a private member variable. 0:32 A great quote found in the JUnit frequently ask questions is this. 0:36 Test until fear turns to boredom. 0:40 Don't feel like you need to test 100% of your code. 0:42 Especially the bits that can't break. 0:45 There are actually tools that fall into the category of test coverage. 0:48 Now they will report on parts of the code that didn't get executed 0:51 during your test run. 0:55 Thus proving that they aren't actually proven to work. 0:56 Usually in these tools, you'll find that your code is actually exercised anyway. 0:59 Check the teachers notes for more coverage on coverage. 1:04 So what happens when you want to test code that relies on other code? 1:08 Now if you don't do anything about it at all 1:13 in the best possible situation assuming the other code is tested as well. 1:15 You end up testing the same code twice during your test run. 1:20 Now let's start imaging some worse situations. 1:23 What happens if something other than that code breaks? 1:27 Does that mean the code you were testing specifically is broken? 1:30 It doesn't mean that, right? 1:33 The problem is actually somewhere else and 1:35 it really should be the responsibility of another test. 1:36 Our code should be isolated to ensure that we are testing 1:40 only the behavior that we are expecting. 1:43 When a test fails for outside reasons, trusts in the test begin to dwindle. 1:46 If tests aren't trusted, errors will be ignored. 1:51 You want trust in your tests, it's why wrote them after all! 1:55 So an even worse situation, 1:59 what if that other code takes a really long time to run and set up? 2:01 That means we're paying for the timing hit when we don't need to. 2:06 If tests don't run fast, they don't get run. 2:09 It's a sad fact, you can put a lot of work into your test, but 2:13 if they don't get run because it takes too long it's simply just wasted work. 2:16 So how do you work around this, how do you make sure that you are only testing 2:21 the behavior that you intend to and you isolate it from everything else? 2:24 Well the answer is test doubles. 2:28 Test doubles can be though of like a stunt double for your test. 2:31 They are used to replace actual code with code that looks and 2:34 behaves pretty similar to the original. 2:38 Sometimes there are different levels of testing that are required to 2:40 fake things out. 2:43 Let's talk through the different types and 2:44 then we'll look at a few that we be able to employ in our app. 2:46 The first two test double patterns are usually hand rolled. 2:50 Fake objects actually have working implementations but 2:53 take shortcuts to make things a little faster. 2:57 Now this can be a reimplementation of a database so that it all runs in memory. 3:00 And Stubs match the needed api for the test but 3:04 usually just respond with a canned answer and only work in a specific use case. 3:07 This is handy for heavy calculations or places that might network connectivity. 3:13 Instead of performing anything they just immediately return the same 3:18 answer every time. 3:21 Now, these next two are usually provided by a third party library. 3:23 Spies are basically fancier stubs that also record some information based on how 3:27 they were used. 3:32 You can verify that things happened, and that they happened in a certain order. 3:33 Mocks are designed with expectations that 3:38 form a specification of the calls they are expected to receive. 3:41 They can throw an exception if they're used in a way that wasn't expected and 3:45 are also checked during verification to insure that they got 3:49 all the calls they were expected. 3:52 We've been focusing on the components but we haven't yet 3:54 taken a look at the vending machine itself. 3:57 One of the things that happens on a proper vend is that a notification 4:00 is sent to text on every successful item sale. 4:03 Let's make sure that we put a test double in place so 4:07 that every time something is vended in our test ed don't send a notification to them. 4:09 He wouldn't like that. 4:13 So if we open up our vending machine class and we take a look 4:15 here in the constructor we'll notice that notifier is the first parameter. 4:20 So let's go ahead and look at the notifier definition. 4:25 Oh, sweet it's an interface, so any implementation of notifier 4:29 as long as it implements the methods defined here right? 4:33 Which is just on sale it'll work. 4:36 Now I wrote things this way specifically for this purpose but 4:38 it is indeed a best practice. 4:43 But, this is a form of what is known as dependency injection, or DI. 4:45 This is called constructor dependency injection, and it allows you to easily 4:50 switch out implementations as needed, and it's super-handy for test doubles. 4:54 We'll talk about this a lot more in upcoming courses but for 4:59 now, just know that this class is setup specifically to allow us to push in 5:01 exactly how we want our notifier to work. 5:06 So, actually this pattern would normally also, right this constructor 5:08 would normally also take a chooser and a creditor and the constructor right? 5:14 So, you can build this machine however you want which is kinda how it works in 5:17 real life, right? 5:20 I mean remember, there's all sorts of different machine types. 5:21 Ones where you can pay with your phone and 5:23 ones where you can choose with a large button, but you could push those in there. 5:25 A dependency injection is one way to tackle this concept of configuration. 5:28 Okay, enough talking. 5:33 So let's rock out a test picture for this vending machine. 5:34 So I'm gonna do, Cmd+Shift+T and create a new test. 5:38 Vending machine test. 5:41 Let's go ahead and set it up, okay. 5:42 All right, so we'll go ahead and make a field for the vending machine. 5:45 And just to recall from before, let's go ahead and make an inline class. 5:54 Okay, so remember you can put a class inside of a class. 6:02 So let's do that. 6:04 We're not gonna use it anywhere else outside of here. 6:08 And we're gonna make sure that it implements the Notifier. 6:10 And it's saying that it doesn't implement, so let's just go ahead and I'm gonna say 6:15 Implement methods because that will say everything inside of this requires this. 6:18 So we'll go ahead and say on sale, and on sale returns a void. 6:22 So we don't actually need to do anything. 6:28 We don't want it do anything, right? 6:30 So let's just say, return. 6:32 Okay, and now in our setup, 6:33 in our before method here let's go ahead and make a new Notifier. 6:35 And see how I'm able to access the class above, right, it knows about it. 6:43 So we'll create a new machine. 6:49 It's going to take the notifier that we just created and 6:53 we'll just put ten, ten, ten in there. 6:56 Right? For rows, columns and back. 7:00 So and let's go ahead and let's restock it as well. 7:02 This will be part of the arrangement. 7:05 In A1 we want some Twinkies. 7:07 I really should have went for product placement on this, right? 7:10 Okay and let's test our happy path right. 7:16 Let's go ahead and let's get some of those delicious Twinkies. 7:19 So we'll go ahead and say, 7:22 Make a new test called vendingWhenStockedReturnsItem. 7:28 And let's add some money, 7:37 a little bit more arranging here, put 75 cents in there. 7:41 And then let's get the item out. 7:46 And then let's make sure that we get our delicious Twinkies up. 8:00 Okay, let's go ahead and run that. 8:13 And if we look back at the vending machine we'll see that when we called vend, 8:19 it did call notifier onSale item. 8:23 And all we did was just return. 8:25 Our implementation, right immediately when it called that it returned, 8:27 instead of connect into the internet in sending a message, it just simply return. 8:30 So we stabbed out the method so 8:35 it won't take forever as well, as it won't notify for 8:38 text that someone bought Twinkies every single time this test was run, right? 8:41 Pretty cool, isn't it? 8:45 Oh, and while we're here, let's look at that method refund money, can that break? 8:46 No, not really. 8:53 And it should already be tested in the Creditor test, right? 8:54 So we don't need to test it here. 8:58 Test until fear turn to boredom. 8:59 I'm not afraid of method. 9:02 Testing that would definitely be boring. 9:03 If we wanted to, we could ensure that when vend was called 9:07 that the appropriate notification was sent. 9:10 We do that by creating a mock. 9:13 You could definitely create your own mock, right? 9:16 All we'd need to do is add some private fields to our stub class and then set 9:18 those fields and access them later to make sure that the method was called. 9:21 Tread lightly here, the more you do this, the harder it gets. 9:25 Because of this difficulty there are awesome Mocking Libraries available. 9:29 If this is something you're interested in learning more about please check 9:33 the teachers notes. 9:36
You need to sign up for Treehouse in order to download course files.Sign up