WEBVTT 00:00:17.060 --> 00:00:19.740 ERIK MICHAELS-OBER: OK. Is the mic live? Yeah? We're good. 00:00:19.740 --> 00:00:26.740 OK. Hi everybody. Welcome. Thank you for coming. So, 00:00:28.890 --> 00:00:33.989 this is gonna be a talk about tools. And 00:00:33.989 --> 00:00:37.970 there's this common expression that says that a carpenter 00:00:37.970 --> 00:00:41.720 is only as good as his or her tools. 00:00:41.720 --> 00:00:43.600 I'm not a carpenter, but that makes a lot 00:00:43.600 --> 00:00:46.190 of sense to me. If your hammer is made 00:00:46.190 --> 00:00:49.320 out of feathers, you're not gonna be able to 00:00:49.320 --> 00:00:51.489 build very much. 00:00:51.489 --> 00:00:54.860 And I really think the same thing is true 00:00:54.860 --> 00:00:58.869 for programmers. I know that that is true. The 00:00:58.869 --> 00:01:02.960 tools that we use really enable us to do 00:01:02.960 --> 00:01:06.070 our job. And we use so many tools, it's 00:01:06.070 --> 00:01:08.509 easy to sort of take for granted the tools 00:01:08.509 --> 00:01:10.210 that we have and the tools that we do 00:01:10.210 --> 00:01:13.229 use. And so I think it's worth sort of 00:01:13.229 --> 00:01:15.159 thinking about the tools that we have and how 00:01:15.159 --> 00:01:18.950 they help us improve as a programmer. And thinking 00:01:18.950 --> 00:01:21.780 about what new tools we can use. In this 00:01:21.780 --> 00:01:25.799 case, I'll be talking specifically about mutation testing and 00:01:25.799 --> 00:01:27.960 how that, as a tool, can really help us 00:01:27.960 --> 00:01:31.999 all improve as programmers. Help us write better tests. 00:01:31.999 --> 00:01:35.060 But, I think, I just want to sort of 00:01:35.060 --> 00:01:36.979 take some time to reflect and, and set a 00:01:36.979 --> 00:01:39.780 little bit of a context for the tools that 00:01:39.780 --> 00:01:41.630 we use every day and sort of, I think 00:01:41.630 --> 00:01:43.850 take for granted a bit. 00:01:43.850 --> 00:01:49.740 So, the first one is an editor. And it 00:01:49.740 --> 00:01:52.350 seems like a very simple tool, right. You just 00:01:52.350 --> 00:01:53.609 type in text and it just shows up on 00:01:53.609 --> 00:01:57.499 the screen. But it's incredibly sophisticated. If you've ever 00:01:57.499 --> 00:01:59.179 tried to write a text editor, if you've ever 00:01:59.179 --> 00:02:01.490 read the source code of a text editor, most 00:02:01.490 --> 00:02:04.189 text editors are like millions of lines of code 00:02:04.189 --> 00:02:08.199 to implement what seems like a relatively simple thing. 00:02:08.199 --> 00:02:09.880 And they help us. They provide us with things 00:02:09.880 --> 00:02:14.680 like syntax highlighting, auto completion. And this directly helps 00:02:14.680 --> 00:02:17.940 us write better programs, right. We avoid bugs. We'll 00:02:17.940 --> 00:02:20.700 realize a bug in our editor before we, before 00:02:20.700 --> 00:02:23.230 we deploy it to production. Before we even run 00:02:23.230 --> 00:02:25.810 tests, we'll find a bug in our editor. Because 00:02:25.810 --> 00:02:29.659 our editor tells us about it. 00:02:29.659 --> 00:02:36.659 This is an early version of Vim. So it 00:02:36.909 --> 00:02:38.900 can, it can be really easy to forget sort 00:02:38.900 --> 00:02:40.989 of what these tools used to look like, right. 00:02:40.989 --> 00:02:44.049 This is how people used to write code. And 00:02:44.049 --> 00:02:45.629 these look more like the sort of tools from 00:02:45.629 --> 00:02:47.379 the wood shop than the tools that we're used 00:02:47.379 --> 00:02:51.010 to using. So this is an early punch card 00:02:51.010 --> 00:02:54.959 machine. The photo was taken in the, in the 00:02:54.959 --> 00:02:59.230 computer history museum in Mountainview, California. And I can 00:02:59.230 --> 00:03:01.260 tell you for a fact that I would not 00:03:01.260 --> 00:03:03.269 be a programmer today if this is how we 00:03:03.269 --> 00:03:05.700 still had to write programs. And I suspect that 00:03:05.700 --> 00:03:08.530 many of you would not be programmers if this 00:03:08.530 --> 00:03:11.599 was sort of the state-of-the-art in how it was 00:03:11.599 --> 00:03:12.189 done. 00:03:12.189 --> 00:03:14.930 And so I think, like, I want to make 00:03:14.930 --> 00:03:17.250 the case that sort of both the quality and 00:03:17.250 --> 00:03:20.549 the quantity of software would be much worse than 00:03:20.549 --> 00:03:22.590 it is today, if not for sort of the 00:03:22.590 --> 00:03:28.189 continued evolution of, of our tools. 00:03:28.189 --> 00:03:30.459 Another tool I use every day is an interactive 00:03:30.459 --> 00:03:34.640 debugger. So, sort of allows you to step through 00:03:34.640 --> 00:03:37.250 your code, line by line, and better understand how 00:03:37.250 --> 00:03:39.060 it works. You can kind of get inside the 00:03:39.060 --> 00:03:42.629 code, right. I'm not gonna spend too much time 00:03:42.629 --> 00:03:48.370 talking about debuggers. Sort of a public service announcement, 00:03:48.370 --> 00:03:51.579 next week, not next week. This week. Next Thursday. 00:03:51.579 --> 00:03:55.359 This Thursday. In this same room, I believe, is 00:03:55.359 --> 00:03:59.700 a great talk on debugger-driven development with Pry. So, 00:03:59.700 --> 00:04:01.810 if you're interested in hearing more about that, you 00:04:01.810 --> 00:04:03.359 should go to that. 00:04:03.359 --> 00:04:07.209 So, what do we do when our code is 00:04:07.209 --> 00:04:11.049 slow? What's the tool for that, right? We have 00:04:11.049 --> 00:04:14.459 profilers that tell us where time is being spent 00:04:14.459 --> 00:04:17.160 when we execute our code. And I wouldn't even 00:04:17.160 --> 00:04:20.750 know how to start optimizing the program if I 00:04:20.750 --> 00:04:22.990 didn't have a profile, right, profiler. I would be 00:04:22.990 --> 00:04:26.570 a terrible optimizer without a profiler. I guess I 00:04:26.570 --> 00:04:30.360 would like start putting in, you know, t equals 00:04:30.360 --> 00:04:33.080 time dot now, and then, like, at the end 00:04:33.080 --> 00:04:36.250 of whatever I wanted to measure, I would subtract 00:04:36.250 --> 00:04:39.569 the current time from the start time. But, that's 00:04:39.569 --> 00:04:42.650 crazy. Like, instrumenting your entire code that way is, 00:04:42.650 --> 00:04:46.650 yeah. Like, I wouldn't really know how to optimize 00:04:46.650 --> 00:04:48.590 code without a profiler. I wouldn't be as good 00:04:48.590 --> 00:04:51.590 at it. None of us would be. 00:04:51.590 --> 00:04:57.490 And another sort of tool that is very prevalent 00:04:57.490 --> 00:05:00.530 in the, in the Ruby community is testing. This 00:05:00.530 --> 00:05:02.810 is an example of someone who should have done 00:05:02.810 --> 00:05:09.810 more testing. So that, again, just. Yeah. All right. 00:05:11.720 --> 00:05:15.060 So I think this is a good illustration of 00:05:15.060 --> 00:05:19.590 how testing can save you, right. Test so that 00:05:19.590 --> 00:05:22.310 you find out before you sort of run it 00:05:22.310 --> 00:05:24.160 in production. OK. 00:05:24.160 --> 00:05:26.000 Enough of that. 00:05:26.000 --> 00:05:28.060 So, I would, I'm actually gonna make the case 00:05:28.060 --> 00:05:30.780 that, in the Ruby, Ruby toolbox, or maybe in 00:05:30.780 --> 00:05:33.699 the Rubyist's toolbox, tests are sort of like the 00:05:33.699 --> 00:05:35.449 hammer, right. Like, this is the thing you turn 00:05:35.449 --> 00:05:38.740 to all the time for all sorts of things. 00:05:38.740 --> 00:05:41.970 We use them to prevent regressions. We use them 00:05:41.970 --> 00:05:45.199 to specify behavior. And we actually use them to 00:05:45.199 --> 00:05:50.490 drive development. DHH doesn't do this, but many others 00:05:50.490 --> 00:05:52.830 do. And find it useful. 00:05:52.830 --> 00:05:57.310 So if we write tests, then we have perfect 00:05:57.310 --> 00:06:00.250 code, right. If we have tests that verify that 00:06:00.250 --> 00:06:02.880 our code does what it's supposed to do, then 00:06:02.880 --> 00:06:05.050 at the end of the day, we have perfect 00:06:05.050 --> 00:06:09.729 code. Correct? Not correct. 00:06:09.729 --> 00:06:13.330 This is the fundamental logical flaw with testing, right. 00:06:13.330 --> 00:06:17.389 You have some code. And you know that code 00:06:17.389 --> 00:06:19.490 can have bugs. So you say I have an 00:06:19.490 --> 00:06:23.139 idea, let's write some tests. But tests are just 00:06:23.139 --> 00:06:26.580 more code. And we know that code has bugs. 00:06:26.580 --> 00:06:29.000 So we're screwed. 00:06:29.000 --> 00:06:31.430 What's that? 00:06:31.430 --> 00:06:35.669 Test your tests. That's right. So. I'm getting there. 00:06:35.669 --> 00:06:36.490 Patience. 00:06:36.490 --> 00:06:40.470 So, like, one tool that people use to sort 00:06:40.470 --> 00:06:43.389 of measure the effectiveness of their tests is code 00:06:43.389 --> 00:06:49.620 coverage. And it's sort of a metric that's designed 00:06:49.620 --> 00:06:52.190 to tell you whether your tests do what they're 00:06:52.190 --> 00:06:55.690 supposed to do. But I'll show you, in a 00:06:55.690 --> 00:06:58.110 moment, why I think it's a really flawed metric 00:06:58.110 --> 00:06:59.750 and why it sort of can give you a 00:06:59.750 --> 00:07:03.270 false sense of security, right. A lot of people 00:07:03.270 --> 00:07:07.180 think that they have 100% code coverage, and that 00:07:07.180 --> 00:07:09.110 means, like, their code is perfect and bug-free. Or 00:07:09.110 --> 00:07:10.919 if they reach that level, then their code will 00:07:10.919 --> 00:07:13.900 be perfect and bug-free. But this is not true. 00:07:13.900 --> 00:07:17.030 Right, like, this guy thinks he's covered and he's 00:07:17.030 --> 00:07:18.110 not. 00:07:18.110 --> 00:07:20.639 And code coverage is actually, like, it's something that 00:07:20.639 --> 00:07:23.599 was built into Ruby, right. Like, in Ruby 1.9.3, 00:07:23.599 --> 00:07:25.919 this is something that, like, we as a programmer 00:07:25.919 --> 00:07:28.280 community said, like, we want to have. And I'm 00:07:28.280 --> 00:07:30.509 not against it. Like, I think it's good. But 00:07:30.509 --> 00:07:32.759 I do think it can give you a false 00:07:32.759 --> 00:07:34.250 sense of security, right. 00:07:34.250 --> 00:07:37.720 I thought this was a funny Tweet. 00:07:37.720 --> 00:07:42.810 So, you can have 100% code coverage and still 00:07:42.810 --> 00:07:49.810 have completely bug-ridden code. So, so is there hope 00:07:50.990 --> 00:07:54.190 for us? Right? Like, how do we, how do 00:07:54.190 --> 00:07:56.960 we test our tests? It's sort of this problem 00:07:56.960 --> 00:07:59.610 of, like, who will watch the watchers, right? Who 00:07:59.610 --> 00:08:01.680 do we, who can we trust? If we can't 00:08:01.680 --> 00:08:04.500 trust our tests, how, why, why are we even 00:08:04.500 --> 00:08:05.930 writing them? 00:08:05.930 --> 00:08:07.930 And I'm gonna try to make the case that 00:08:07.930 --> 00:08:12.259 mutation testing is the sort of solution to this 00:08:12.259 --> 00:08:17.840 problem. So just like everything else, like an editor, 00:08:17.840 --> 00:08:22.039 like an interactive debugger, like a profiler, like tests, 00:08:22.039 --> 00:08:26.050 mutation testing is a tool. The basic idea behind 00:08:26.050 --> 00:08:28.080 it is that it takes your tests and it 00:08:28.080 --> 00:08:31.759 runs them against your code, and they should pass. 00:08:31.759 --> 00:08:33.330 And if they do pass, then what it does, 00:08:33.330 --> 00:08:35.320 is it takes your code and it makes a 00:08:35.320 --> 00:08:38.880 modification to your code. It actually changes your code 00:08:38.880 --> 00:08:42.530 at runtime. And then it runs your tests again, 00:08:42.530 --> 00:08:45.670 against the modified version of your code. And the 00:08:45.670 --> 00:08:48.330 idea is that when that code is modified, the 00:08:48.330 --> 00:08:52.130 tests that previously passed should now fail, right. 00:08:52.130 --> 00:08:55.120 So the thing, your modified code is called a 00:08:55.120 --> 00:08:57.490 mutant, and the idea is that if that test 00:08:57.490 --> 00:09:00.540 fails, you kill the mutant. Right. The mutant dies. 00:09:00.540 --> 00:09:02.860 But if that mutant survives, then that means there's 00:09:02.860 --> 00:09:05.190 something wrong with your tests. There might not be 00:09:05.190 --> 00:09:07.310 something wrong with your code. But there is certainly 00:09:07.310 --> 00:09:09.640 something wrong with your tests. Either you have a 00:09:09.640 --> 00:09:12.480 bug in your tests. You have missing tests. Your 00:09:12.480 --> 00:09:16.620 tests are either over-specified or under-specified. 00:09:16.620 --> 00:09:18.800 So this is a technique, it's very helpful for 00:09:18.800 --> 00:09:21.579 sort of answering the question, what tests should I 00:09:21.579 --> 00:09:24.620 write? Which I think is a question that many 00:09:24.620 --> 00:09:27.510 of us struggle with. It's certainly something that beginners 00:09:27.510 --> 00:09:29.860 struggle with when they're starting to program. Like, how 00:09:29.860 --> 00:09:32.690 do I, how do I write tests? What, what 00:09:32.690 --> 00:09:34.920 do I test? Right. 00:09:34.920 --> 00:09:36.529 And then there's also this question of like, how 00:09:36.529 --> 00:09:38.800 do I know when I'm done? How do I 00:09:38.800 --> 00:09:42.490 know when the code is sufficiently tested? And I 00:09:42.490 --> 00:09:45.839 think these are actually hard questions to ask, or 00:09:45.839 --> 00:09:51.040 hard questions to answer, and mutation, mutation testing provides 00:09:51.040 --> 00:09:54.339 a, a quantitative answer to those questions. You can 00:09:54.339 --> 00:09:59.380 say, with confidence, that this code has 100% mutation 00:09:59.380 --> 00:10:02.450 coverage. 00:10:02.450 --> 00:10:09.260 So, just to sort of give an example, here 00:10:09.260 --> 00:10:13.820 is some code. And an assertion about the code. 00:10:13.820 --> 00:10:16.600 So, I have a method, foo. It takes an 00:10:16.600 --> 00:10:20.940 argument whose default is true. And the actual method 00:10:20.940 --> 00:10:26.440 body for foo is either return that argument or 00:10:26.440 --> 00:10:33.089 fail. And my assertion says assert_nothing_raised if I call 00:10:33.089 --> 00:10:37.940 the method foo without passing in any parameters. 00:10:37.940 --> 00:10:40.480 And so, or without passing in any arguments to 00:10:40.480 --> 00:10:47.480 the, our parameter, rather. And so what, you know, 00:10:48.070 --> 00:10:52.430 this test will pass, right. Arg. You call foo. 00:10:52.430 --> 00:10:55.420 Arg is true. And it sort of short-circuits, right. 00:10:55.420 --> 00:10:59.560 It sees arg. It sees the or. And this 00:10:59.560 --> 00:11:02.860 test passes. So maybe you think this is a 00:11:02.860 --> 00:11:05.550 good test. Maybe you think you're done writing your 00:11:05.550 --> 00:11:08.410 tests. But you are not. 00:11:08.410 --> 00:11:11.070 And a mutant of that code, a small modification, 00:11:11.070 --> 00:11:13.829 a sort of unit modification of that code might 00:11:13.829 --> 00:11:17.220 look like this. And basically what it did was 00:11:17.220 --> 00:11:19.440 it just sort of took that or fail and 00:11:19.440 --> 00:11:21.910 removed it. And the idea is like, if you 00:11:21.910 --> 00:11:25.130 do that, at least one of your tests should 00:11:25.130 --> 00:11:27.589 now, that was passing before, should now fail. One 00:11:27.589 --> 00:11:30.200 of your tests over that code, for that foo 00:11:30.200 --> 00:11:33.600 method, should now fail. And if it does not, 00:11:33.600 --> 00:11:37.700 then you are not testing your code sufficiently. 00:11:37.700 --> 00:11:42.339 So, this is called a statement deletion mutation. There 00:11:42.339 --> 00:11:46.670 are various other types of mutation. So, for example, 00:11:46.670 --> 00:11:49.820 there are mutations that would take that default parameter 00:11:49.820 --> 00:11:52.149 and change it from true to false, or from 00:11:52.149 --> 00:11:56.320 true to nil, right. Which would also cause failure, 00:11:56.320 --> 00:11:58.970 in this case. 00:11:58.970 --> 00:12:01.290 There's another mutation that will take the or and 00:12:01.290 --> 00:12:04.540 change it to an and, right. So any time 00:12:04.540 --> 00:12:07.519 there is sort of a unit in your code, 00:12:07.519 --> 00:12:10.050 it takes greater than signs and changes them to 00:12:10.050 --> 00:12:12.949 less than or equal to signs, et cetera. Right. 00:12:12.949 --> 00:12:15.820 It takes ifs and changes them to unless. It 00:12:15.820 --> 00:12:18.180 will take whole expressions and negate them and make 00:12:18.180 --> 00:12:21.139 sure that your tests fail when the negation of 00:12:21.139 --> 00:12:25.339 a statement is, when, when the method returns the 00:12:25.339 --> 00:12:28.430 negation of the statement instead of the statement, right. 00:12:28.430 --> 00:12:30.660 So that's, that's sort of the core idea behind 00:12:30.660 --> 00:12:34.040 mutation testing. And so you end up sort of 00:12:34.040 --> 00:12:37.500 writing these tests to cover all these cases that, 00:12:37.500 --> 00:12:39.839 and then you sort of know when you're done, 00:12:39.839 --> 00:12:42.589 right. Like, you know when all of your tests, 00:12:42.589 --> 00:12:46.860 when, when your code is fully mutation-covered. 00:12:46.860 --> 00:12:51.500 This is another Tweet. It's one from Katrina Owen. 00:12:51.500 --> 00:12:53.839 And it's sort of this idea, it's kind of 00:12:53.839 --> 00:12:56.709 like both horrifying and satisfying at the same time. 00:12:56.709 --> 00:12:59.360 But if you sort of add more granular tests, 00:12:59.360 --> 00:13:03.139 you'll find more bugs. And in many cases, mutant, 00:13:03.139 --> 00:13:05.350 which is a mutation testing framework, will find those 00:13:05.350 --> 00:13:07.940 bugs for you. Right. That's cool. 00:13:07.940 --> 00:13:10.350 OK. So I promised there would be live-coding. This 00:13:10.350 --> 00:13:13.560 is sort of. The introduction is over and now 00:13:13.560 --> 00:13:17.070 we will write some code. Hopefully. 00:13:17.070 --> 00:13:24.070 I'm just gonna switch to mirror display. Command F1. 00:13:32.949 --> 00:13:36.870 That is a protip. That's great. You're a pro. 00:13:36.870 --> 00:13:41.430 I clearly am not. OK. Cool. 00:13:41.430 --> 00:13:44.459 Cool. And a new version of mutant was, like, 00:13:44.459 --> 00:13:48.649 just released a few minutes ago, in advance of 00:13:48.649 --> 00:13:53.389 this presentation. I am not the author of mutant. 00:13:53.389 --> 00:13:56.570 It's a great library by Markus Schirp, and I 00:13:56.570 --> 00:13:59.740 encourage you all to check it out. Version zero 00:13:59.740 --> 00:14:03.170 dot five dot eleven, hot off the presses. 00:14:03.170 --> 00:14:07.889 So this is some code. So, like, the, this 00:14:07.889 --> 00:14:10.579 sort of thrust behind this live-coding demo is I 00:14:10.579 --> 00:14:13.329 will not be live-coding code, I will be live-coding 00:14:13.329 --> 00:14:16.690 tests. Because the idea is not to, like, mutant 00:14:16.690 --> 00:14:18.899 doesn't verify that your code is correct. It verifies 00:14:18.899 --> 00:14:20.570 that your tests are correct. So you still need 00:14:20.570 --> 00:14:23.420 to write tests, right. Tests verify that your code 00:14:23.420 --> 00:14:26.130 is correct. Mutant verifies that your tests are correct. 00:14:26.130 --> 00:14:28.699 So this is the code. And it's pretty, pretty 00:14:28.699 --> 00:14:32.550 simple. But we'll sort of walk through it line-by-line. 00:14:32.550 --> 00:14:34.240 Just to make sure everyone has a good understanding 00:14:34.240 --> 00:14:39.190 of it. And so there's this module that represents 00:14:39.190 --> 00:14:42.839 the universe, the entire universe, and inside of the 00:14:42.839 --> 00:14:45.139 universe we have planets. And that's what this class 00:14:45.139 --> 00:14:49.139 is all about. It's a pretty simple planet. It 00:14:49.139 --> 00:14:54.920 takes a radius and an area as parameters when 00:14:54.920 --> 00:14:59.040 it's constructed and stores those in instance variables. The 00:14:59.040 --> 00:15:02.620 radius is the mean radius of the planet and, 00:15:02.620 --> 00:15:05.740 in kilometers, and the area is sort of surface 00:15:05.740 --> 00:15:10.300 area of the planet in square kilometers. 00:15:10.300 --> 00:15:13.630 And then there's one sort of interesting method, one 00:15:13.630 --> 00:15:20.630 public method, spherical. And spherical will return true if, 00:15:22.540 --> 00:15:26.339 if the planet is a perfect sphere, or within 00:15:26.339 --> 00:15:29.130 a particular tolerance of that. So the idea is 00:15:29.130 --> 00:15:32.649 we calculate the approximate area using four pi r 00:15:32.649 --> 00:15:37.130 squared, which is the formula to calculate the area 00:15:37.130 --> 00:15:43.839 of a sphere, and if the area sort of 00:15:43.839 --> 00:15:47.029 matches that, then we know it's a sphere. We 00:15:47.029 --> 00:15:50.480 know it's spherical. This method returns true. 00:15:50.480 --> 00:15:53.480 And if, if that's not true, then the planet 00:15:53.480 --> 00:15:56.899 is not spherical. It's either oblate, like the earth, 00:15:56.899 --> 00:16:02.110 or prolate, and then this method will return false. 00:16:02.110 --> 00:16:04.389 So, yeah. We just sort of calculate the approximate 00:16:04.389 --> 00:16:07.110 area and then we have this ranged private method 00:16:07.110 --> 00:16:10.100 that just generates a range. We need sort a 00:16:10.100 --> 00:16:12.069 tolerance. The idea is you don't want it to 00:16:12.069 --> 00:16:16.899 be too precise, because we're dealing with pi, so 00:16:16.899 --> 00:16:22.750 pi is, I mean, in actuality, it's a non-terminating 00:16:22.750 --> 00:16:26.630 number. In Ruby, it has, like, ten digits of 00:16:26.630 --> 00:16:28.839 precision or something like that, right. Like the constant 00:16:28.839 --> 00:16:29.740 map pi. 00:16:29.740 --> 00:16:33.110 But the idea is that, like, if it's close 00:16:33.110 --> 00:16:35.589 enough to a sphere, within a particular tolerance, then 00:16:35.589 --> 00:16:39.620 we'll just call it round, basically. And so we 00:16:39.620 --> 00:16:43.509 generate this range, which is sort of the approximate 00:16:43.509 --> 00:16:46.720 area that we've calculated, based on the radius plus 00:16:46.720 --> 00:16:49.470 or minus the tolerance, and we see if the 00:16:49.470 --> 00:16:53.160 area falls within those bounds. Does everyone understand this 00:16:53.160 --> 00:16:55.690 code? I think it is pretty simple. I tried 00:16:55.690 --> 00:16:58.110 to make it fit on one screen. On one 00:16:58.110 --> 00:16:59.459 slide. 00:16:59.459 --> 00:17:00.810 Yeah? 00:17:00.810 --> 00:17:05.220 OK. So if everyone understands it, I want to 00:17:05.220 --> 00:17:06.530 take a little bit of a poll. This is 00:17:06.530 --> 00:17:08.550 kind of like the interactive part of the talk. 00:17:08.550 --> 00:17:10.849 And you have to, like, everyone has to participate. 00:17:10.849 --> 00:17:14.829 That's the, that's the goal. Everyone, people like to 00:17:14.829 --> 00:17:17.030 sort of sit by the sidelines and not commit, 00:17:17.030 --> 00:17:19.339 but you have to commit. I'll be really angry 00:17:19.339 --> 00:17:22.540 if you don't. 00:17:22.540 --> 00:17:26.230 You don't want to see me angry. 00:17:26.230 --> 00:17:28.950 So how many tests do you think you need 00:17:28.950 --> 00:17:34.650 to fully cover this code? To cover the public 00:17:34.650 --> 00:17:38.670 method, the, the spherical method, right, so that it's 00:17:38.670 --> 00:17:41.750 sort of fully exercised. Who thinks you need zero 00:17:41.750 --> 00:17:48.750 tests? Show of hands? Anybody? No. Good. I agree. 00:17:48.890 --> 00:17:52.270 You can't cover code without tests. So, that's good. 00:17:52.270 --> 00:17:53.680 You've been paying some attention. 00:17:53.680 --> 00:17:56.620 Who thinks you can do it with one test? 00:17:56.620 --> 00:17:59.670 Maybe, sort of, the happy path? Right. You write 00:17:59.670 --> 00:18:04.370 a test that says, you know, you expect some 00:18:04.370 --> 00:18:08.640 planet to be spherical given radius and an area, 00:18:08.640 --> 00:18:15.640 and it is. All good. Who thinks that's sufficient? 00:18:17.550 --> 00:18:19.790 Nobody. So. 00:18:19.790 --> 00:18:23.700 You can actually get C-zero, 100% C-zero code coverage 00:18:23.700 --> 00:18:26.900 of this entire class with one test. With one 00:18:26.900 --> 00:18:31.430 spec. Right. You won't have 100% mutation coverage, but 00:18:31.430 --> 00:18:32.810 I will show you, in a minute, you can 00:18:32.810 --> 00:18:36.270 have 100% C-zero code coverage, despite the fact that 00:18:36.270 --> 00:18:38.670 nobody in this room thinks that that is sufficient 00:18:38.670 --> 00:18:41.650 to cover this code. So. I will prove it 00:18:41.650 --> 00:18:44.260 to you. But you all intuitively know this to 00:18:44.260 --> 00:18:47.180 be the case. And yet we all idolize this 00:18:47.180 --> 00:18:50.810 C-zero code coverage metric as if it means something, 00:18:50.810 --> 00:18:54.120 when really it, it's a false sense of security, 00:18:54.120 --> 00:18:56.420 right. You're the guy with the umbrella in the 00:18:56.420 --> 00:18:59.450 hurricane, and the umbrella is like destroyed and inside 00:18:59.450 --> 00:19:00.640 out. 00:19:00.640 --> 00:19:04.730 OK. So how many people think you can do 00:19:04.730 --> 00:19:10.050 it with two tests? OK. Somebody who's raising your 00:19:10.050 --> 00:19:12.150 hand. This gentleman in the front. What are the 00:19:12.150 --> 00:19:13.500 two tests that you would write? Just sort of 00:19:13.500 --> 00:19:17.640 roughly? Maybe the happy path and what other? 00:19:17.640 --> 00:19:20.120 AUDIENCE: One that's spherical and one not. 00:19:20.120 --> 00:19:21.620 E.M.: One that's spherical and one that's not. OK. 00:19:21.620 --> 00:19:24.170 I think that's good. How many people think you 00:19:24.170 --> 00:19:27.820 would need three to do it? K, maybe gentleman 00:19:27.820 --> 00:19:29.580 there who thinks we need three. What's the third 00:19:29.580 --> 00:19:32.540 you would write? 00:19:32.540 --> 00:19:36.640 AUDIENCE: [indecipherable - 00:19:41] 00:19:36.640 --> 00:19:43.470 E.M.: Say it again? A value for tolerance? 00:19:43.470 --> 00:19:46.080 AUDIENCE: A value that will blow up the computation. 00:19:46.080 --> 00:19:46.960 E.M.: That will blow up the computation. How would 00:19:46.960 --> 00:19:49.040 you blow up the computation? 00:19:49.040 --> 00:19:53.860 AUDIENCE: [indecipherable - 00:19:55] 00:19:53.860 --> 00:19:56.410 E.M.: Passing in a string. 00:19:56.410 --> 00:19:58.110 AUDIENCE: Yes. 00:19:58.110 --> 00:20:02.030 E.M.: OK. Great. And what would you expect the 00:20:02.030 --> 00:20:04.390 result to be, like, what would your expectation, what 00:20:04.390 --> 00:20:06.380 would you assert? Like, I pass in a string 00:20:06.380 --> 00:20:08.700 and I expect. 00:20:08.700 --> 00:20:11.650 AUDIENCE: An exception to be raised. 00:20:11.650 --> 00:20:12.640 E.M.: An exception. OK. And if you didn't get 00:20:12.640 --> 00:20:15.840 an exception then that would be a problem. 00:20:15.840 --> 00:20:17.510 AUDIENCE: Yes. 00:20:17.510 --> 00:20:24.270 E.M.: OK. OK. Who thinks four will do it? 00:20:24.270 --> 00:20:26.500 Nobody thinks four will do it. A few people 00:20:26.500 --> 00:20:33.500 do. Yeah. What additional tests would you add? 00:20:33.650 --> 00:20:40.250 AUDIENCE: Well, you're testing a range, so you have- 00:20:40.250 --> 00:20:40.290 E.M.: Hmm. Great. 00:20:40.290 --> 00:20:40.370 AUDIENCE: -so there's two sides. 00:20:40.370 --> 00:20:41.010 E.M.: I really like this. So, the comment was 00:20:41.010 --> 00:20:43.070 that you're testing a range, and there's sort of 00:20:43.070 --> 00:20:45.180 two sides. There's the, I'm on the low-end of 00:20:45.180 --> 00:20:46.680 the range and I am included, and I am 00:20:46.680 --> 00:20:49.600 on the high-end of the range. So it would 00:20:49.600 --> 00:20:52.800 be, there's two of those. Right. One for the 00:20:52.800 --> 00:20:54.150 low-end and one for the high-end. Exactly. 00:20:54.150 --> 00:20:56.950 So, it's sort of the happy path. The thing 00:20:56.950 --> 00:20:59.770 is spherical. The sad path, the thing is not 00:20:59.770 --> 00:21:04.580 spherical. And both sides of the range. I like 00:21:04.580 --> 00:21:08.260 that. Good. How many people think five? Five or 00:21:08.260 --> 00:21:11.080 more? How's that? Five or more. OK. Lots of 00:21:11.080 --> 00:21:12.980 hands for five or more. 00:21:12.980 --> 00:21:19.590 So, according to mutant, which is also software, therefore 00:21:19.590 --> 00:21:23.180 imperfect, you can, you can test this with four, 00:21:23.180 --> 00:21:25.790 and it will not handle things like you should, 00:21:25.790 --> 00:21:29.280 like, it sort of assumes that the radius and 00:21:29.280 --> 00:21:33.840 area are valid, right. Like, you can, although, actually, 00:21:33.840 --> 00:21:36.190 maybe that's. Well, we can try it. It's a 00:21:36.190 --> 00:21:37.850 live coding thing. So let's just do it and 00:21:37.850 --> 00:21:41.310 see what happens. But thank you for participating in 00:21:41.310 --> 00:21:43.520 that. I think it was an interesting exercise. 00:21:43.520 --> 00:21:47.170 But, yeah. Basically, like, mutant says the answer to 00:21:47.170 --> 00:21:50.170 this question is four, right. It's basically the happy 00:21:50.170 --> 00:21:52.280 path, the sad path, and both sides of the 00:21:52.280 --> 00:21:57.650 range. So yeah. Let's, let's sort of show how 00:21:57.650 --> 00:22:00.980 that works. 00:22:00.980 --> 00:22:07.720 OK. So I'm gonna start by just making a 00:22:07.720 --> 00:22:10.420 gemfile, as you do. So let me, I can 00:22:10.420 --> 00:22:16.310 just sort of show. It's a very simple layout 00:22:16.310 --> 00:22:18.600 so far. I have a lib directory, which contains 00:22:18.600 --> 00:22:23.160 universe dot rb, which you've all seen. And a 00:22:23.160 --> 00:22:26.220 spec directory which is empty. So, very little up 00:22:26.220 --> 00:22:28.360 my sleeve at this point. 00:22:28.360 --> 00:22:35.360 I'm just gonna make a gemfile, as you do. 00:22:41.190 --> 00:22:43.070 And at this point I'm just gonna add rspec, 00:22:43.070 --> 00:22:45.550 cause I'm starting to write some tests, and I'm 00:22:45.550 --> 00:22:48.130 gonna add mutant. 00:22:48.130 --> 00:22:55.130 OK. So, and we'll bundle install. Ah. Cool. It 00:22:59.280 --> 00:23:02.540 just installed that new version of mutant that was 00:23:02.540 --> 00:23:06.380 just released moments ago. Good. Let me just see 00:23:06.380 --> 00:23:12.190 what Ruby version I'm on. OK. That should be 00:23:12.190 --> 00:23:13.040 fine. 00:23:13.040 --> 00:23:15.020 So. Let's write some specs. So we have the 00:23:15.020 --> 00:23:21.370 spec directory. Let's write planet_spec dot rb. And we'll 00:23:21.370 --> 00:23:26.280 require rspec and we'll require our planet file. I'll 00:23:26.280 --> 00:23:29.350 just use require_relative for that, rather than messing with 00:23:29.350 --> 00:23:31.180 the load path or anything. So that's up a 00:23:31.180 --> 00:23:36.150 directory in lib and I think it's called universe. 00:23:36.150 --> 00:23:40.960 And now let's start writing our specs, right. So 00:23:40.960 --> 00:23:47.960 we're just gonna describe our planet in our universe 00:23:48.490 --> 00:23:55.490 model. And. So let's create a subject, which is 00:23:59.430 --> 00:24:02.120 just gonna be our planet. That's like the main 00:24:02.120 --> 00:24:04.530 thing that we're gonna be testing here. And it's 00:24:04.530 --> 00:24:08.400 initialized with a radius and an area. I believe 00:24:08.400 --> 00:24:12.200 in that order. Yup. 00:24:12.200 --> 00:24:19.200 Cool. So let's create a context. And let's do 00:24:20.160 --> 00:24:22.250 the happy path first, because that was kind of, 00:24:22.250 --> 00:24:24.490 like, we all agreed that the first path we 00:24:24.490 --> 00:24:27.610 should write was the happy path. So in this 00:24:27.610 --> 00:24:32.470 case, Venus is actually the happy path. Venus is 00:24:32.470 --> 00:24:36.680 pretty darn close to spherical. So in this case 00:24:36.680 --> 00:24:43.680 we'll define the radius to be. Oops. Cool. 00:25:00.520 --> 00:25:04.660 And I think I said it's in meters, yeah? 00:25:04.660 --> 00:25:10.660 So it'll be that. And then the area will 00:25:10.660 --> 00:25:17.660 be. Eh, let's see. Wikipedia. OK. So the surface 00:25:26.860 --> 00:25:33.800 area is, what is that? Four-hundred sixty million? Which 00:25:33.800 --> 00:25:37.050 is OK. But actually, like, I would like a 00:25:37.050 --> 00:25:39.900 more precise number, because, like, I don't want to 00:25:39.900 --> 00:25:42.310 crank up our tolerance to some ridiculous value to 00:25:42.310 --> 00:25:45.000 make this true. So I actually found a more 00:25:45.000 --> 00:25:48.180 precise number than the one that's on Wikipedia, which 00:25:48.180 --> 00:25:51.840 is this. So it's four-hundred sixty million, two hundred 00:25:51.840 --> 00:25:55.180 sixty-four thousand, seven-hundred forty. Which is, you know, pretty 00:25:55.180 --> 00:25:58.000 round number still, but it's more precise than the 00:25:58.000 --> 00:26:01.130 one on Wikipedia. 00:26:01.130 --> 00:26:03.290 And now we'll have our assertion. So we'll just 00:26:03.290 --> 00:26:10.170 say it's spherical. Venus is spherical. We expect our 00:26:10.170 --> 00:26:17.170 subject to be spherical. Good? Is everyone satisfied? Do 00:26:18.850 --> 00:26:20.900 I, like, if people see bugs, call them out. 00:26:20.900 --> 00:26:23.420 Like, does this look like a good happy path 00:26:23.420 --> 00:26:28.400 test? Yes? This will pass? 00:26:28.400 --> 00:26:35.400 Good. Let's run it. Yup. That should work. Cool. 00:26:39.590 --> 00:26:42.540 It passed. Hooray. 00:26:42.540 --> 00:26:45.150 Let's do something else. Let's open up our gemfile 00:26:45.150 --> 00:26:49.160 again and add simplecov to measure the C-0 code 00:26:49.160 --> 00:26:56.160 coverage. And I guess here we can just say 00:26:56.820 --> 00:27:03.420 require simplecov. SimpleCov.start. And so now, if we run 00:27:03.420 --> 00:27:10.420 our specs again, we'll get a little coverage report. 00:27:11.160 --> 00:27:16.530 Tada! 00:27:16.530 --> 00:27:19.040 So for those who aren't that familiar with simplecov, 00:27:19.040 --> 00:27:24.350 basically it looks to make sure that your, that 00:27:24.350 --> 00:27:26.430 every line of code is executed, and if you 00:27:26.430 --> 00:27:30.380 test the happy path, it totally is, right? The 00:27:30.380 --> 00:27:34.210 class, the module is loaded, the class is loaded, 00:27:34.210 --> 00:27:41.210 this constant is set. We initialize. We initialize a 00:27:41.490 --> 00:27:45.590 planet. I can turn on lines. We initialize a 00:27:45.590 --> 00:27:51.140 planet on line nine. We invoke this spherical method 00:27:51.140 --> 00:27:56.140 on line fifteen, in the assertion. And that invokes 00:27:56.140 --> 00:27:59.050 the range method. So we have, you can actually 00:27:59.050 --> 00:28:02.350 see every line of code is executed precisely one 00:28:02.350 --> 00:28:04.290 time. 00:28:04.290 --> 00:28:07.070 So we have, we're not over-testing. We're not under-testing. 00:28:07.070 --> 00:28:11.070 We have perfect, a hundred percent C-zero code coverage. 00:28:11.070 --> 00:28:14.050 But we all agreed that this was completely insufficient. 00:28:14.050 --> 00:28:14.650 So- 00:28:14.650 --> 00:28:16.450 AUDIENCE: Ship it. 00:28:16.450 --> 00:28:19.450 E.M.: Ship it. K. Right. 00:28:19.450 --> 00:28:21.250 AUDIENCE: Force push. 00:28:21.250 --> 00:28:27.280 E.M.: I'm gonna delete this simplecov stuff cause it's 00:28:27.280 --> 00:28:29.130 garbage. 00:28:29.130 --> 00:28:33.750 OK. So let's write some more tests. So a 00:28:33.750 --> 00:28:40.750 planet that's not spherical is. No. That's my name. 00:28:41.010 --> 00:28:48.010 Thank you. Is our home. The earth. Radius of 00:28:52.590 --> 00:28:59.590 the earth. Cool. I guess we could say point 00:29:06.200 --> 00:29:13.200 one. Doesn't really matter. And. Oops. What's the area? 00:29:22.050 --> 00:29:29.050 Cool. So in square kilometers, it's five-hundred ten. Five-hundred 00:29:31.910 --> 00:29:36.520 ten million, rather. 00:29:36.520 --> 00:29:38.090 So we, again, we could, like, try to find 00:29:38.090 --> 00:29:40.290 a number that's more precise, but we actually, like, 00:29:40.290 --> 00:29:42.640 the whole point of this test is to test 00:29:42.640 --> 00:29:45.450 a planet that is an oblate spheroid, not an 00:29:45.450 --> 00:29:48.460 actual sphere. And so in this case, we want 00:29:48.460 --> 00:29:50.790 to, so like, it's fine that the numbers are 00:29:50.790 --> 00:29:56.050 not within the default tolerance. And so, yeah. Basically 00:29:56.050 --> 00:30:00.120 we want to say, like, it is oblate. Not 00:30:00.120 --> 00:30:06.470 spherical. 00:30:06.470 --> 00:30:10.530 So in this case, we expect our subject not 00:30:10.530 --> 00:30:17.530 to be spherical. Cool. Look good? Let's run it. 00:30:21.750 --> 00:30:27.770 Cool. Our tests pass. 00:30:27.770 --> 00:30:31.990 So this is, like, maybe your normal workflow. You 00:30:31.990 --> 00:30:33.470 would do this. A few of you would stop 00:30:33.470 --> 00:30:35.050 at this point. I think there were probably as 00:30:35.050 --> 00:30:37.400 many hands for, like, I would stop at two, 00:30:37.400 --> 00:30:39.250 or probably more tests, for like, I would stop 00:30:39.250 --> 00:30:42.170 at two, than I would stop at four or 00:30:42.170 --> 00:30:45.470 three. But let me show, let me show what 00:30:45.470 --> 00:30:46.170 mutant does. 00:30:46.170 --> 00:30:47.950 Let me show sort of how this mutation testing 00:30:47.950 --> 00:30:53.640 stuff works. So you're gonna say bundle exec. Or, 00:30:53.640 --> 00:30:57.890 I have it aliased to b-e. I can spell 00:30:57.890 --> 00:31:02.040 that out. So this is the mutant command line, 00:31:02.040 --> 00:31:04.910 and it takes a bunch of arguments. So you 00:31:04.910 --> 00:31:07.390 have to give it a lib for the sort 00:31:07.390 --> 00:31:09.370 of lib directory that you're testing so that it 00:31:09.370 --> 00:31:11.970 knows to add that to the load path. And 00:31:11.970 --> 00:31:16.160 then you give it a require. So it's gonna 00:31:16.160 --> 00:31:19.970 require some specific library, in this case the universe 00:31:19.970 --> 00:31:23.800 library that you wrote. And then you can say, 00:31:23.800 --> 00:31:25.990 like, I want to test everything in universe, or 00:31:25.990 --> 00:31:29.540 you can say, like, with wild cards like colon 00:31:29.540 --> 00:31:31.650 colon universe star. I can make that a little 00:31:31.650 --> 00:31:34.240 smaller so it fits on one line. 00:31:34.240 --> 00:31:36.760 Or you can say, like, I want to test 00:31:36.760 --> 00:31:40.700 specifically the planet class, or you say, like, I 00:31:40.700 --> 00:31:42.250 want to test a particular method. So you can 00:31:42.250 --> 00:31:44.990 say, like, I want to test spherical. Something like 00:31:44.990 --> 00:31:47.230 that. Right. But we want to test the whole 00:31:47.230 --> 00:31:48.060 planet class. 00:31:48.060 --> 00:31:50.640 Oh, and you also, there's an option to say 00:31:50.640 --> 00:31:53.750 use rspec, so it knows what test framework to 00:31:53.750 --> 00:31:59.360 run. This is important, because it's testing your tests. 00:31:59.360 --> 00:32:00.630 And I am getting some sort of an error. 00:32:00.630 --> 00:32:04.880 Ah. I am missing mutant-rspec in my gemfile. That 00:32:04.880 --> 00:32:09.630 is easy to fix. Right. So. 00:32:09.630 --> 00:32:12.140 Rspec used to be built in. This has changed 00:32:12.140 --> 00:32:15.640 recently. So basically there are other libraries. There's like 00:32:15.640 --> 00:32:18.450 plugin library. So if you want to write, if 00:32:18.450 --> 00:32:20.800 you use some crazy test-framework, you can just write 00:32:20.800 --> 00:32:23.410 a gem that adds mutant support for that test 00:32:23.410 --> 00:32:25.690 framework. So this happens to be the one for 00:32:25.690 --> 00:32:28.760 rspec. But you can use one for test-unit or 00:32:28.760 --> 00:32:29.590 anything else. 00:32:29.590 --> 00:32:33.030 So. BI is just a short-cut for bundle install. 00:32:33.030 --> 00:32:38.090 And we'll do this. Cool. 00:32:38.090 --> 00:32:40.010 So what it is doing, you're like, what, this 00:32:40.010 --> 00:32:42.860 is crazy. We only wrote two tests. Why are 00:32:42.860 --> 00:32:45.420 there all those little green dots and Fs flying 00:32:45.420 --> 00:32:52.420 by? So basically what's happening is we, it's taking 00:32:53.870 --> 00:32:58.690 our two tests and it's running through these various 00:32:58.690 --> 00:33:01.210 mutations. In this case, it made eight-three mutations to 00:33:01.210 --> 00:33:05.450 our code, based on what we used, right. Like, 00:33:05.450 --> 00:33:08.170 so, depending on, like, if you use an and, 00:33:08.170 --> 00:33:09.420 it will convert it to an or. But if 00:33:09.420 --> 00:33:11.540 you don't use that, you can't, you do that 00:33:11.540 --> 00:33:12.190 mutation. 00:33:12.190 --> 00:33:16.740 So, in this case, there was eighty-three mutations. Eighty-three 00:33:16.740 --> 00:33:18.840 sort of mutants. And eighty-two of those mutants were 00:33:18.840 --> 00:33:23.770 killed. So there, in this case, was one that 00:33:23.770 --> 00:33:27.200 was not. And you get this really cool output, 00:33:27.200 --> 00:33:31.040 diff output. So it basically says, this is the 00:33:31.040 --> 00:33:33.980 mutation we did that was not killed. We took, 00:33:33.980 --> 00:33:40.280 what is it, line twenty-four? Was that? Is there 00:33:40.280 --> 00:33:44.910 a comment? We took line twenty-five, right, this range 00:33:44.910 --> 00:33:50.310 method, and we deleted the code that you wrote 00:33:50.310 --> 00:33:51.790 and we mutated it in this way. We got 00:33:51.790 --> 00:33:54.290 rid of that minus T. And it turned out 00:33:54.290 --> 00:33:56.960 that even after we made that mutation, all of 00:33:56.960 --> 00:33:59.920 your tests still passed. 00:33:59.920 --> 00:34:03.400 Actually, maybe it would be helpful, like, I can 00:34:03.400 --> 00:34:09.530 show with earth. So before we do earth, this 00:34:09.530 --> 00:34:11.750 is what the mutation output would look like. Right. 00:34:11.750 --> 00:34:13.300 So. I just want to give you a sense 00:34:13.300 --> 00:34:15.619 of, like, all the different mutations and kind of 00:34:15.619 --> 00:34:17.690 how they work and what the output looks like. 00:34:17.690 --> 00:34:20.020 So if we don't have the sort of unhappy 00:34:20.020 --> 00:34:23.418 path where it returns false, these are the various 00:34:23.418 --> 00:34:25.520 mutations it runs. So there was this one, which 00:34:25.520 --> 00:34:27.340 we saw earlier, where it removes the minus T 00:34:27.340 --> 00:34:29.570 from the range and it still passes because we're 00:34:29.570 --> 00:34:33.300 sort of in the top half of that range. 00:34:33.300 --> 00:34:35.969 There's this other one where it gets rid of 00:34:35.969 --> 00:34:38.030 the n, so the beginning part of the range, 00:34:38.030 --> 00:34:40.050 and it just puts in t there. 00:34:40.050 --> 00:34:44.290 Here, it actually gets rid of that call to 00:34:44.290 --> 00:34:47.639 dot cover, and it turns out that, because the 00:34:47.639 --> 00:34:49.850 range returns true and you haven't put in a 00:34:49.850 --> 00:34:53.350 thing that says it should return false, that this 00:34:53.350 --> 00:34:56.290 also passes, right. So, in this case, you're just 00:34:56.290 --> 00:34:58.760 returning the range. But that is truthy. And so 00:34:58.760 --> 00:35:02.760 this, this test fails. 00:35:02.760 --> 00:35:05.080 If you wanted to write a more precise test, 00:35:05.080 --> 00:35:08.130 instead of saying. No, I guess that's right. So, 00:35:08.130 --> 00:35:12.230 in this case it's just gonna check whether that 00:35:12.230 --> 00:35:13.890 method is truthy or falsey, and in this case 00:35:13.890 --> 00:35:15.970 it's truthy if it just returns the range. Right? 00:35:15.970 --> 00:35:17.700 And you're not testing that it would ever be 00:35:17.700 --> 00:35:19.770 falsey. 00:35:19.770 --> 00:35:24.370 Also, if you just return the instance variable area, 00:35:24.370 --> 00:35:27.220 so if you basically throw away everything except that 00:35:27.220 --> 00:35:30.830 last argument to the cover method, this turns out 00:35:30.830 --> 00:35:34.550 to also, like, you have no tests that covers 00:35:34.550 --> 00:35:38.710 this. And actually you can delete that whole line, 00:35:38.710 --> 00:35:41.940 and the previous line, approximate area, like you get 00:35:41.940 --> 00:35:43.570 the same result. Like, the fact that you have 00:35:43.570 --> 00:35:45.800 an approximate area and that is truthy and you 00:35:45.800 --> 00:35:48.280 are only testing that this method returns a truthy 00:35:48.280 --> 00:35:52.230 value means that this test will pass. 00:35:52.230 --> 00:35:58.840 So I just wanted to show that. I can 00:35:58.840 --> 00:36:02.030 bring this back. Cool. 00:36:02.030 --> 00:36:05.110 So now we're in a place where, oops. OK. 00:36:05.110 --> 00:36:12.110 So our tests will pass. And we have one 00:36:12.130 --> 00:36:15.920 mutant that we need to kill. So does anyone 00:36:15.920 --> 00:36:18.780 have an idea for how to kill this mutant? 00:36:18.780 --> 00:36:25.780 AUDIENCE: Pass in a tolerance. [indecipherable - 00:36:27] Pass 00:36:26.540 --> 00:36:29.450 in zero tolerance. 00:36:29.450 --> 00:36:32.580 E.M.: So the suggestion was to pass in a 00:36:32.580 --> 00:36:35.730 zero tolerance. So let's try that. So should I 00:36:35.730 --> 00:36:39.620 just, should we make up a planet or, how 00:36:39.620 --> 00:36:41.140 do you want to do that? We could do 00:36:41.140 --> 00:36:41.760 Mars, maybe? 00:36:41.760 --> 00:36:44.490 AUDIENCE: Venus shouldn't be spherical with a tolerance of 00:36:44.490 --> 00:36:46.180 E.M.: Ah. Venus shouldn't be spherical with a tolerance 00:36:46.180 --> 00:36:50.810 of zero. So that's true. So we can sort 00:36:50.810 --> 00:36:53.740 of change this one to be, it is spherical, 00:36:53.740 --> 00:36:55.440 give the default tolerance. 00:36:55.440 --> 00:36:56.880 AUDIENCE: Yes. 00:36:56.880 --> 00:37:01.230 E.M.: That's what that tests. Right. It's spherical-ish. I 00:37:01.230 --> 00:37:04.460 like that. Ish. 00:37:04.460 --> 00:37:11.460 But is not perfectly spherical. And so here we 00:37:16.220 --> 00:37:18.480 would expect this not to be spherical, given a 00:37:18.480 --> 00:37:22.490 tolerance of zero. Yeah? So let's first run that 00:37:22.490 --> 00:37:29.490 test. Cool. So that passes. It is not perfectly 00:37:30.110 --> 00:37:34.900 spherical, and it is spherical-ish. We didn't break that 00:37:34.900 --> 00:37:37.620 test. OK, so now let's do the same thing 00:37:37.620 --> 00:37:44.620 with our mutant command. 00:37:44.840 --> 00:37:50.970 So the mutant still lives. Why? 00:37:50.970 --> 00:37:53.410 So to make this fail, what we need to 00:37:53.410 --> 00:37:56.080 do is we need to pass in a tolerance 00:37:56.080 --> 00:37:58.790 that falls in the bottom half of the range. 00:37:58.790 --> 00:38:03.380 So, in this case, Venus is slightly the area 00:38:03.380 --> 00:38:09.410 of Venus is slightly above the perfect sphericism or 00:38:09.410 --> 00:38:14.020 whatever, right. It's not, it's on the high-end of 00:38:14.020 --> 00:38:15.540 the range. So what we need to do is 00:38:15.540 --> 00:38:19.810 we need to find a planet that is actually 00:38:19.810 --> 00:38:22.460 on the low-end of the range, right, where it's 00:38:22.460 --> 00:38:28.910 less. It's spherical, but within the tolerance, but it's, 00:38:28.910 --> 00:38:33.860 yeah. On the low-end of the range. Make sense? 00:38:33.860 --> 00:38:40.320 So yeah. I don't know. Like, what we could 00:38:40.320 --> 00:38:42.550 do to test, like, we could, I, I don't 00:38:42.550 --> 00:38:44.790 want to necessarily like look up more planets and 00:38:44.790 --> 00:38:49.200 their radiuses. But we could do something like this. 00:38:49.200 --> 00:38:53.460 So this is, sorry, that's not earth. This is, 00:38:53.460 --> 00:38:54.230 like. 00:38:54.230 --> 00:38:56.550 AUDIENCE: Rubinius 5. 00:38:56.550 --> 00:38:59.530 E.M.: Rubinius 5. I like that. Thank you for 00:38:59.530 --> 00:39:04.540 the suggestion from the audience. And Rubinius 5. Let's 00:39:04.540 --> 00:39:06.890 sort of make it easy for ourselves. So we'll 00:39:06.890 --> 00:39:13.810 say the radius is zero point five, right. So 00:39:13.810 --> 00:39:17.080 if we put that in our formula, zero point 00:39:17.080 --> 00:39:21.350 five squared is a quarter, and then a quarter, 00:39:21.350 --> 00:39:26.040 when it sort of cancels out the multiple by 00:39:26.040 --> 00:39:29.210 four. You div, you're dividing by four basically. So 00:39:29.210 --> 00:39:33.190 the, we know that the actual area should be 00:39:33.190 --> 00:39:36.500 pi. So then we can just say something like, 00:39:36.500 --> 00:39:43.500 let the area be Math::PI. And we want it 00:39:44.750 --> 00:39:47.680 to fall, we want the area to be below 00:39:47.680 --> 00:39:49.430 the range. Right, so we want it to be 00:39:49.430 --> 00:39:52.350 like, Math::Pi minus, like, some amount that falls within 00:39:52.350 --> 00:39:56.620 the tolerance or whatever. Right? Make sense? 00:39:56.620 --> 00:40:01.660 And then we expect that this is gonna be 00:40:01.660 --> 00:40:08.660 spherical. Ish. Within the default tolerance. Cool. OK. So 00:40:19.570 --> 00:40:25.760 let's run that. Specs pass. And have we killed 00:40:25.760 --> 00:40:32.510 the last mutant? Nice. Yeah. 00:40:32.510 --> 00:40:36.610 Yeah! So.