WEBVTT 1 00:00:00.090 --> 00:00:01.790 Hi guys and welcome back. 2 00:00:01.790 --> 00:00:03.250 In this video we're going to be implementing 3 00:00:03.250 --> 00:00:05.504 a new function, that we're gonna call multiply, 4 00:00:05.504 --> 00:00:08.370 and we're gonna be writing a few tests for it 5 00:00:08.370 --> 00:00:10.880 with what we know now on boundary value analysis 6 00:00:10.880 --> 00:00:12.878 and equivalence partitioning. 7 00:00:12.878 --> 00:00:15.785 Let's start by writing our function, 8 00:00:15.785 --> 00:00:18.000 which I'm gonna call multiply. 9 00:00:18.000 --> 00:00:19.480 And what it's gonna do is it's gonna take 10 00:00:19.480 --> 00:00:21.781 any number of arguments and each one 11 00:00:21.781 --> 00:00:24.963 is going to be either an int or a float. 12 00:00:26.000 --> 00:00:27.603 Notice that by doing *args, 13 00:00:28.810 --> 00:00:32.250 which by the way you can do *values or *a 14 00:00:32.250 --> 00:00:33.840 or whatever you want, 15 00:00:33.840 --> 00:00:36.840 by doing that this function will be called like this, 16 00:00:36.840 --> 00:00:37.740 three, five, nine. 17 00:00:39.580 --> 00:00:42.340 You can pass in any number of arguments here. 18 00:00:42.340 --> 00:00:45.090 You don't have to pass in a list of arguments 19 00:00:45.090 --> 00:00:45.923 or anything like that. 20 00:00:45.923 --> 00:00:49.479 Just separate individual arguments to this function 21 00:00:49.479 --> 00:00:53.638 is what this star means in front of args. 22 00:00:53.638 --> 00:00:56.037 Okay, so now we've got that, 23 00:00:56.037 --> 00:01:00.300 and we're gonna do is check if the len of args is zero, 24 00:01:00.300 --> 00:01:03.060 and if it is, we're gonna raise a value error, 25 00:01:03.060 --> 00:01:05.590 and we're gonna say at least one value 26 00:01:06.670 --> 00:01:10.070 to multiply must be passed. 27 00:01:10.070 --> 00:01:14.970 And do make sure to use the right brackets there. 28 00:01:14.970 --> 00:01:17.490 Otherwise, we're gonna start at one, 29 00:01:17.490 --> 00:01:20.267 and we're gonna iterate over the arguments, 30 00:01:20.267 --> 00:01:23.890 and we're gonna just multiply total by arg, 31 00:01:23.890 --> 00:01:25.681 and at the end we're gonna return total. 32 00:01:25.681 --> 00:01:30.681 Very naive, very simple multiplication method. 33 00:01:31.060 --> 00:01:32.580 By far not the best one, 34 00:01:32.580 --> 00:01:34.693 but simple enough. 35 00:01:34.693 --> 00:01:36.690 However if you look at this code, 36 00:01:36.690 --> 00:01:38.621 it may not be immediately obvious 37 00:01:38.621 --> 00:01:40.910 everything that it does and potentially 38 00:01:40.910 --> 00:01:43.940 all the different paths that code could take through it. 39 00:01:43.940 --> 00:01:45.645 So, it is always good to write some tests 40 00:01:45.645 --> 00:01:47.561 when you have a function like this one, 41 00:01:47.561 --> 00:01:50.411 so that you can show people that look at the tests 42 00:01:50.411 --> 00:01:52.830 everything that you know about the function. 43 00:01:52.830 --> 00:01:53.971 And also you can set in stone 44 00:01:53.971 --> 00:01:56.363 what you expect the function to, 45 00:01:57.210 --> 00:01:58.850 and also so you can set in stone 46 00:01:58.850 --> 00:02:01.310 how you expect the function to behave. 47 00:02:01.310 --> 00:02:03.636 That way if that changes later on down the line, 48 00:02:03.636 --> 00:02:05.400 some of your tests will fail 49 00:02:05.400 --> 00:02:07.200 and you'll be able to identify exactly 50 00:02:07.200 --> 00:02:08.337 what's changed in your code, 51 00:02:08.337 --> 00:02:10.263 in case you didn't realise. 52 00:02:11.440 --> 00:02:13.838 So, what we'll do is we'll start by testing 53 00:02:13.838 --> 00:02:17.121 a multiplication, where the values 54 00:02:17.121 --> 00:02:19.386 or the argument says empty. 55 00:02:19.386 --> 00:02:21.681 So, we'll say test_multiply_empty, 56 00:02:21.681 --> 00:02:26.681 and then we will come here and say with self.assertRraises 57 00:02:26.780 --> 00:02:31.461 a ValueError, we will just type multiply like that. 58 00:02:31.461 --> 00:02:34.463 And you do need to import it of course. 59 00:02:35.930 --> 00:02:37.670 Now if we run this it should pass 60 00:02:37.670 --> 00:02:40.570 because not passing any arguments 61 00:02:40.570 --> 00:02:43.563 will cause args to have a length of zero. 62 00:02:43.563 --> 00:02:45.710 And then this will raise a value error. 63 00:02:45.710 --> 00:02:48.420 At this point I'm gonna enable this toggle down 64 00:02:48.420 --> 00:02:50.994 on the bottom left so that this reruns every time 65 00:02:50.994 --> 00:02:53.490 I save the file. 66 00:02:53.490 --> 00:02:55.760 Let's go into our second test. 67 00:02:55.760 --> 00:02:58.329 Now that we've tested the empty arguments, 68 00:02:58.329 --> 00:03:01.200 we should also test boundaries around it 69 00:03:01.200 --> 00:03:03.816 or rather the zero argument is the boundary, 70 00:03:03.816 --> 00:03:06.506 so we should test one as well. 71 00:03:06.506 --> 00:03:10.623 So, we're gonna multiply a single value. 72 00:03:13.380 --> 00:03:16.000 So, we'll say that the expected is 15 73 00:03:16.000 --> 00:03:18.698 and we'll say self.assertEqual, 74 00:03:18.698 --> 00:03:23.220 multiply of expected should be the same value as expected. 75 00:03:23.220 --> 00:03:25.105 So, whenever you multiply a single value, 76 00:03:25.105 --> 00:03:26.530 it should be the same. 77 00:03:26.530 --> 00:03:27.830 So, now I'll press save. 78 00:03:27.830 --> 00:03:29.310 The tests will rerun down here 79 00:03:29.310 --> 00:03:32.043 and you can see six of six passed, so this is good. 80 00:03:33.560 --> 00:03:35.968 Next up we will try to multiply zero, 81 00:03:35.968 --> 00:03:38.211 because this could be a boundary 82 00:03:38.211 --> 00:03:40.353 or rather it is a boundary that I've thought 83 00:03:40.353 --> 00:03:42.461 could potentially behave differently 84 00:03:42.461 --> 00:03:44.870 depending on the implementation of the function. 85 00:03:44.870 --> 00:03:47.237 So, we'll say test_multiply_zero, 86 00:03:50.136 --> 00:03:55.136 and we will go for zero here and type assertEqual, 87 00:03:55.710 --> 00:04:00.710 multiply of expected should be expected. 88 00:04:00.840 --> 00:04:03.620 What this means is if you pass in zero 89 00:04:03.620 --> 00:04:05.020 to the multiply function, 90 00:04:05.020 --> 00:04:07.654 it is still going to multiply whatever way 91 00:04:07.654 --> 00:04:10.616 it is using to multiply by zero, 92 00:04:10.616 --> 00:04:13.380 and that means you're always gonna get zero back. 93 00:04:13.380 --> 00:04:15.940 I can see how some incorrect implementations 94 00:04:15.940 --> 00:04:18.873 of a multiply function could potentially return one 95 00:04:18.873 --> 00:04:20.136 in this scenario. 96 00:04:20.136 --> 00:04:24.460 Not something you would expect but it could happen. 97 00:04:24.460 --> 00:04:26.535 Next up, we are going to just test 98 00:04:26.535 --> 00:04:29.330 the multiply function does the correct thing. 99 00:04:29.330 --> 00:04:32.370 So, we will go ahead and give the inputs, 100 00:04:32.370 --> 00:04:34.410 which are gonna be three and five in my case, 101 00:04:34.410 --> 00:04:36.443 and the expected result which is gonna be 15. 102 00:04:36.443 --> 00:04:38.773 And then we'll say self.assertEqual, 103 00:04:39.690 --> 00:04:44.690 the multiply with the inputs will be the expected value. 104 00:04:44.814 --> 00:04:46.810 Notice that I've made a mistake here on purpose, 105 00:04:46.810 --> 00:04:48.460 just to show you a couple of things. 106 00:04:48.460 --> 00:04:49.778 The first one is that I saved the file 107 00:04:49.778 --> 00:04:52.880 and the tests ran and one of them fails, 108 00:04:52.880 --> 00:04:56.240 and you get here the error message. 109 00:04:56.240 --> 00:05:01.240 So, you'll see that 15 is not equal to three, five. 110 00:05:01.471 --> 00:05:04.472 So, evidently the function returned three, five, 111 00:05:04.472 --> 00:05:06.663 and not 15, which is what we were expecting. 112 00:05:06.663 --> 00:05:11.320 So, that is because we didn't pass in the numbers. 113 00:05:11.320 --> 00:05:14.170 What we passed in is the tuple of the numbers. 114 00:05:14.170 --> 00:05:16.910 what we want to do is pass in three and five as separate 115 00:05:16.910 --> 00:05:20.100 arguments like this, and in order to do that with 116 00:05:20.100 --> 00:05:22.220 inputs, you need to do *inputs, 117 00:05:22.220 --> 00:05:25.680 and that is going to pass exactly these values 118 00:05:25.680 --> 00:05:27.823 as individual arguments. 119 00:05:29.143 --> 00:05:33.735 Next up, we are going to include a zero in our inputs. 120 00:05:33.735 --> 00:05:38.030 So, we will say inputs are three, five, and zero. 121 00:05:38.030 --> 00:05:40.222 And the expected result is zero. 122 00:05:40.222 --> 00:05:44.440 So, a very simple test, but nonetheless 123 00:05:44.440 --> 00:05:46.675 probably a necessary one. 124 00:05:46.675 --> 00:05:49.580 Just in case there is a check for zero in the inputs 125 00:05:49.580 --> 00:05:50.750 or something like that, 126 00:05:50.750 --> 00:05:53.315 you can think that it's quite similar to the multiply zero. 127 00:05:53.315 --> 00:05:55.850 But in this case it is with more inputs here. 128 00:05:55.850 --> 00:05:58.636 We just want to make sure that our loop isn't 129 00:05:58.636 --> 00:06:01.490 for example, ignoring zero values, 130 00:06:01.490 --> 00:06:04.170 which I can see an implementation doing potentially 131 00:06:04.170 --> 00:06:06.560 if it was done incorrectly. 132 00:06:06.560 --> 00:06:10.280 Next up, we are going to multiply negative values, 133 00:06:10.280 --> 00:06:14.780 and we will expect the results to be minus 30 in this case. 134 00:06:14.780 --> 00:06:17.340 So, there is another equivalence class there, 135 00:06:17.340 --> 00:06:21.484 minus five, which you probably should test for. 136 00:06:21.484 --> 00:06:24.540 You can do things like test for double negative values 137 00:06:24.540 --> 00:06:26.641 making sure it is positive and so on, 138 00:06:26.641 --> 00:06:29.352 but that is probably getting too much 139 00:06:29.352 --> 00:06:32.723 into does maths work in Python? 140 00:06:33.768 --> 00:06:35.960 It's up to you how much, how deep 141 00:06:35.960 --> 00:06:38.850 you want to go into this with these values, 142 00:06:38.850 --> 00:06:40.730 but I wouldn't put too many in there, 143 00:06:40.730 --> 00:06:44.670 just enough to check for the boundaries themselves. 144 00:06:44.670 --> 00:06:48.690 Finally we are going to multiply some floats 145 00:06:48.690 --> 00:06:50.710 because that is another class here. 146 00:06:50.710 --> 00:06:52.640 So, we'll do 3.0 and two, 147 00:06:52.640 --> 00:06:55.450 and to make sure that the output isn't floored 148 00:06:55.450 --> 00:06:57.940 or rounded or anything like that, 149 00:06:57.940 --> 00:06:59.597 so the expect is gonna be 6.0, 150 00:06:59.597 --> 00:07:02.400 and we will do assertEqual 151 00:07:02.400 --> 00:07:05.880 the multiply of inputs and the expected. 152 00:07:05.880 --> 00:07:08.290 So, a couple more things you could do here, 153 00:07:08.290 --> 00:07:11.067 of course have different types of inputs like strings 154 00:07:11.067 --> 00:07:13.780 or tuples or lists and so on. 155 00:07:13.780 --> 00:07:16.933 Potentially you may want to check the multiply function 156 00:07:16.933 --> 00:07:20.170 and make sure that these things are only ints and floats. 157 00:07:20.170 --> 00:07:22.635 You could have a type check inside the function, 158 00:07:22.635 --> 00:07:26.920 but those things are taken care of 159 00:07:26.920 --> 00:07:28.312 by the type hinting. 160 00:07:28.312 --> 00:07:32.427 So, as long as the developer has type hinting enabled 161 00:07:32.427 --> 00:07:34.605 when they try to call your multiply function 162 00:07:34.605 --> 00:07:36.630 with a string, for example they should 163 00:07:36.630 --> 00:07:38.620 get a message saying you know this function 164 00:07:38.620 --> 00:07:40.240 only takes ints some floats. 165 00:07:40.240 --> 00:07:42.160 So, you don't have to test things 166 00:07:42.160 --> 00:07:46.201 that are already taken care of by the static analysis 167 00:07:46.201 --> 00:07:48.340 in this case the type hinting. 168 00:07:48.340 --> 00:07:52.300 This is why type hinting is a pretty popular thing nowadays 169 00:07:52.300 --> 00:07:54.562 and it's a very useful thing to have in your code base, 170 00:07:54.562 --> 00:07:58.200 and it's something that Python hasn't had for a long time, 171 00:07:58.200 --> 00:08:00.006 at least not official support for. 172 00:08:00.006 --> 00:08:02.586 So, do make sure that you use type hinting, 173 00:08:02.586 --> 00:08:04.649 especially on functions, 174 00:08:04.649 --> 00:08:07.248 because they can really help you 175 00:08:07.248 --> 00:08:10.510 and they can really prevent errors down the line. 176 00:08:10.510 --> 00:08:13.167 For example if you define this multiply function 177 00:08:13.167 --> 00:08:15.910 in a specific way, and somebody uses in that way 178 00:08:15.910 --> 00:08:17.735 that you don't expect, such as by passing a string 179 00:08:17.735 --> 00:08:20.744 or a tuple, you could get some errors in here 180 00:08:20.744 --> 00:08:23.010 that could easily be avoided just by showing 181 00:08:23.010 --> 00:08:25.040 the developer a nice message. 182 00:08:25.040 --> 00:08:27.702 So, for now that's our tests. 183 00:08:27.702 --> 00:08:29.618 If you can think of any more questions 184 00:08:29.618 --> 00:08:31.413 you'd like to ask your function, 185 00:08:31.413 --> 00:08:34.200 and make sure that it does it over time, 186 00:08:34.200 --> 00:08:37.280 as your code changes do add those in here. 187 00:08:37.280 --> 00:08:39.131 If you are thinking that there's a lot of repetition 188 00:08:39.131 --> 00:08:41.882 in these tests, you would be correct. 189 00:08:41.882 --> 00:08:43.305 There is quite a lot of repetition 190 00:08:43.305 --> 00:08:46.750 in the inputs and outputs and self assertEqual. 191 00:08:46.750 --> 00:08:49.120 All of these tests do the same thing. 192 00:08:49.120 --> 00:08:51.840 So, there are Python libraries to reduce this duplication, 193 00:08:51.840 --> 00:08:54.230 but they are not covered in this course. 194 00:08:54.230 --> 00:08:56.700 I'm sure that you can learn about them by looking 195 00:08:56.700 --> 00:08:58.946 at official documentation and things like that. 196 00:08:58.946 --> 00:09:01.999 For example a library called hypothesis comes to mind 197 00:09:01.999 --> 00:09:04.063 exactly to do that. 198 00:09:05.260 --> 00:09:06.093 That's it for this video dude. 199 00:09:06.093 --> 00:09:07.123 Thanks for joining me. 200 00:09:07.123 --> 00:09:08.573 I'll see you on the next one.