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