1 00:00:00,980 --> 00:00:03,900 So it is time to write some functional tests. 2 00:00:03,900 --> 00:00:05,940 Are you ready, I know I am. 3 00:00:05,940 --> 00:00:08,620 So typically these tests are written to prove 4 00:00:08,620 --> 00:00:13,740 to people who requested features that things are operating as they expect. 5 00:00:13,740 --> 00:00:18,406 So what we want to prove here is that when someone makes a web request to 6 00:00:18,406 --> 00:00:22,589 a specific URI or resource, that certain actions happens and 7 00:00:22,589 --> 00:00:25,335 the correct status codes are returned. 8 00:00:25,335 --> 00:00:27,230 Right, so that's all we're testing here functionally. 9 00:00:28,310 --> 00:00:32,240 Now, what makes things a little hard here in Spark land is that our routes 10 00:00:32,240 --> 00:00:37,150 are lambdas as well as they accept some of these carefully request and 11 00:00:37,150 --> 00:00:38,776 response objects, right? 12 00:00:38,776 --> 00:00:42,650 Some frameworks provide a handy way to perform this testing. 13 00:00:42,650 --> 00:00:45,920 But alas our little little microframework here does not. 14 00:00:45,920 --> 00:00:48,330 So like we often have to do in microframework land, 15 00:00:48,330 --> 00:00:50,510 we have to craft our own solution. 16 00:00:50,510 --> 00:00:52,670 So let's start by making a test right? 17 00:00:52,670 --> 00:00:57,979 So we'll come here to this API and we will do command shift t. 18 00:00:57,979 --> 00:01:04,170 We'll say create test, That's great, let's go ahead and do an before and an after. 19 00:01:04,170 --> 00:01:07,012 We know we're going to need those later and we'll click OK. 20 00:01:09,735 --> 00:01:13,414 Okay, so one thing I wanna do here is actually start our sever up and 21 00:01:13,414 --> 00:01:17,810 the way we do that is by calling the main method right, in our API class. 22 00:01:17,810 --> 00:01:20,930 We're gonna keep our server running for all of these tests, all right, 23 00:01:20,930 --> 00:01:22,580 we're not gonna start it and stop it. 24 00:01:22,580 --> 00:01:26,357 So we're going to use an annotation called BeforeClass. 25 00:01:26,357 --> 00:01:30,623 So this will run once before any test run and only once after it's all done. 26 00:01:30,623 --> 00:01:35,206 So we're gonna call it BeforeClass and it's going to be a static class, or 27 00:01:35,206 --> 00:01:37,160 a static method sorry. 28 00:01:37,160 --> 00:01:40,960 And it's gonna be called startServer cuz you can name whatever you want, 29 00:01:40,960 --> 00:01:41,680 we want to make sense. 30 00:01:41,680 --> 00:01:47,276 So here we're just going to call that main methods, we're going to say Api.main. 31 00:01:47,276 --> 00:01:50,920 Okay and it takes arguments, and right now we don't have any. 32 00:01:50,920 --> 00:01:52,717 So we're gonna say null and 33 00:01:52,717 --> 00:01:56,840 remember that's an array of strings that that accepts. 34 00:01:56,840 --> 00:02:01,220 So let's also stop it when we are done, so we 'll say AfterClass. 35 00:02:01,220 --> 00:02:03,590 And again we can name this whatever we want but 36 00:02:03,590 --> 00:02:07,960 I think it's probably best if we call it stopServer, seems to make sense. 37 00:02:07,960 --> 00:02:09,772 It's clear, anybody can look at that and know what that is. 38 00:02:09,772 --> 00:02:14,167 And there is a static method off of Spark called stop. 39 00:02:16,547 --> 00:02:20,153 And it's talking about, we're talking about Spark Spark. 40 00:02:20,153 --> 00:02:23,993 [SOUND] Okay, so let's take a quick look at what this is gonna do. 41 00:02:23,993 --> 00:02:29,058 If we flip over to our Api.java and we look in here, this is the main method 42 00:02:29,058 --> 00:02:34,719 that it's gonna call and it's gonna create a connection to the database. 43 00:02:34,719 --> 00:02:35,830 And it's the file database, 44 00:02:35,830 --> 00:02:37,969 that means any time our test runs it would write in there. 45 00:02:37,969 --> 00:02:40,460 We don't wanna do that, that's no good. 46 00:02:40,460 --> 00:02:43,180 We need some way to configure this. 47 00:02:43,180 --> 00:02:44,880 You know what the other thing is? 48 00:02:44,880 --> 00:02:48,690 This is always gonna run on port four, five, six, seven, but 49 00:02:48,690 --> 00:02:53,090 we know that if you try to run the server while the server is running, it blows up. 50 00:02:53,090 --> 00:02:55,600 So we can't do that, we need to configure both of those. 51 00:02:55,600 --> 00:02:57,130 So we need some way to do this. 52 00:02:58,910 --> 00:03:01,360 Now just so you know, there are great ways to do this. 53 00:03:01,360 --> 00:03:04,070 There's third-party configuration libraries out there, 54 00:03:04,070 --> 00:03:07,240 Apache Commons Configuration is the most popular one. 55 00:03:07,240 --> 00:03:08,880 Check the teacher's notes for some more of these. 56 00:03:08,880 --> 00:03:11,880 But let's go ahead and do something pretty simple here. 57 00:03:11,880 --> 00:03:15,210 And later we can implement one of those custom configurations if we wanted to. 58 00:03:15,210 --> 00:03:17,934 So we do have a way to push settings into our API and 59 00:03:17,934 --> 00:03:20,798 that's through the arguments passed in, right? 60 00:03:20,798 --> 00:03:24,130 We can pass something in there because we're calling it on the other side. 61 00:03:24,130 --> 00:03:29,050 So let's do that, let's come over back to the test. 62 00:03:29,050 --> 00:03:33,016 And where we're passing something here, let's go ahead and 63 00:03:33,016 --> 00:03:34,931 let's make a new array here. 64 00:03:34,931 --> 00:03:41,020 We'll say, string of and we'll call it args, we call it whatever we want. 65 00:03:41,020 --> 00:03:43,570 And let's go ahead and let's set the port. 66 00:03:43,570 --> 00:03:48,340 We'll set the string, so we're gonna put it in there, we'll say 4568 for the port. 67 00:03:48,340 --> 00:03:55,260 And let's set up the jdbc:h2, we want in memory for sure, we want that to be fast. 68 00:03:55,260 --> 00:03:57,650 And we'll just name it testing like we did before. 69 00:03:57,650 --> 00:03:59,750 So, there's that and we'll pass args in. 70 00:04:01,690 --> 00:04:03,810 You know what, this number looks a little magic doesn't it? 71 00:04:03,810 --> 00:04:06,070 Let's go ahead and that's always a bad thing. 72 00:04:06,070 --> 00:04:12,880 So let's go ahead and we'll choose Refactor, and we will Extract, Constant. 73 00:04:14,240 --> 00:04:22,320 And we wanna this PORT, and we'll go ahead and also extract the constant here. 74 00:04:23,420 --> 00:04:27,140 So we'll do Refactor, Extract, Constant. 75 00:04:28,150 --> 00:04:36,510 And we are going to call this TEST_DATASOURCE just to be super clear. 76 00:04:36,510 --> 00:04:39,009 Cool, and if we look up at the top here those are exposed and 77 00:04:39,009 --> 00:04:41,929 now somebody reading this understands what it is that we are doing. 78 00:04:41,929 --> 00:04:44,410 And you can change it in one place should we use this elsewhere. 79 00:04:46,490 --> 00:04:51,090 Okay, so now in our API class we have some arguments that are passed in right? 80 00:04:51,090 --> 00:04:55,211 So why don't we right here say if args.length, 81 00:04:55,211 --> 00:05:02,257 cuz you don't have to pass anything in and if we don't we want it to run like normal. 82 00:05:02,257 --> 00:05:07,003 So if there are args.length we know that the first one is the port, right, so 83 00:05:07,003 --> 00:05:08,110 we'll say port. 84 00:05:09,170 --> 00:05:16,810 And we will do Integer.parse, because we passed in a string, args[0]. 85 00:05:16,810 --> 00:05:22,640 And port is a static method off of Spark. 86 00:05:22,640 --> 00:05:25,253 So, that will set the port that the server runs on. 87 00:05:25,253 --> 00:05:28,998 Now the second parameter is a little bit trickier and actually, why don't we move 88 00:05:28,998 --> 00:05:32,100 this right up by the arguments, that's kind of the best practice. 89 00:05:32,100 --> 00:05:34,100 So let's move that above these guys here. 90 00:05:36,030 --> 00:05:38,280 The second argument is the data source, right? 91 00:05:38,280 --> 00:05:42,260 So, we're gonna go ahead and let's set what the default data source is. 92 00:05:42,260 --> 00:05:43,557 So, I'm gonna grab this. 93 00:05:45,918 --> 00:05:49,438 And we will pop that up here, we'll say String datasource. 94 00:05:54,678 --> 00:05:59,982 Okay, so since there are two, we're gonna set specifically 95 00:05:59,982 --> 00:06:04,984 the data source to what was passed in if it's there, right. 96 00:06:04,984 --> 00:06:08,020 Now do you see anything wrong with this code, maybe we need to be more careful. 97 00:06:08,020 --> 00:06:13,120 So if something's passed in and args.length isn't equal to 2, 98 00:06:13,120 --> 00:06:16,150 they didn't pass both the parameters. 99 00:06:16,150 --> 00:06:18,350 We need them to pass it, otherwise we'll blow up here. 100 00:06:18,350 --> 00:06:23,034 So we'll do a, we'll tell them how to use it better, right, usage instructions. 101 00:06:23,034 --> 00:06:28,290 Let's say java Api, and we're expecting a port, and we're expecting a data source. 102 00:06:28,290 --> 00:06:31,120 And this is just kinda what we'll print out 103 00:06:31,120 --> 00:06:35,360 on the command line if they try to press something there and let's exit. 104 00:06:35,360 --> 00:06:40,050 Why keep going if we haven't passed in two arguments. 105 00:06:40,050 --> 00:06:44,330 Cool, so now we'll use some string formatting here to our benefit. 106 00:06:44,330 --> 00:06:51,749 We'll say String.format and we'll put back in that data source, right? 107 00:06:51,749 --> 00:06:54,670 Boy, there's a lot of quotes going on in here, isn't there? 108 00:06:54,670 --> 00:06:58,990 Always a little bit dangerous there, so we're gonna pass on the datasource and 109 00:06:58,990 --> 00:06:59,750 then finish that off. 110 00:07:00,980 --> 00:07:02,973 There we go, that looks good. 111 00:07:07,479 --> 00:07:09,270 Okay, we're getting so close. 112 00:07:09,270 --> 00:07:11,270 So if we flip back over to the ApiTest, and 113 00:07:11,270 --> 00:07:13,020 we'll jump back into our before method. 114 00:07:13,020 --> 00:07:16,930 Now remember that we need to keep the connection open or 115 00:07:16,930 --> 00:07:18,260 the database will be erased each time. 116 00:07:18,260 --> 00:07:19,230 We don't wanna do that. 117 00:07:19,230 --> 00:07:21,680 So, what we should do is we should make a new connection and 118 00:07:21,680 --> 00:07:24,020 open it up and keep it open for each test. 119 00:07:24,020 --> 00:07:27,120 And then therefore when the test is over, the database will get erased. 120 00:07:27,120 --> 00:07:28,890 It'll work kinda like magic, right? 121 00:07:28,890 --> 00:07:35,780 So we'll say, Sql2o sql2o = new Sql2o. 122 00:07:36,890 --> 00:07:40,340 Hey look we get to use our TEST_DATASOURCE there. 123 00:07:41,380 --> 00:07:46,330 And we want to also make sure that we do that INIT again. 124 00:07:48,120 --> 00:07:50,120 Probably should put this in function someplace right? 125 00:07:50,120 --> 00:07:54,659 I feel like I've written it enough, RUNSCRIPT from, 126 00:07:54,659 --> 00:07:59,307 we wanna remember both, classpath:db/init.sql. 127 00:07:59,307 --> 00:08:02,780 And we wanna remember that final trailing quote there, awesome. 128 00:08:05,060 --> 00:08:11,570 And then we're gonna open up a connection that we can close, sql2o.open. 129 00:08:16,890 --> 00:08:19,535 This is going to be a private field. 130 00:08:21,518 --> 00:08:22,297 That is fine. 131 00:08:24,377 --> 00:08:28,400 All right, and then we want to close it after each test. 132 00:08:28,400 --> 00:08:31,560 So remember the before class is running before all the tests run, and 133 00:08:31,560 --> 00:08:36,720 this is before and after are running, before each test and after each test. 134 00:08:36,720 --> 00:08:44,610 Awesome, okay so it's about time to craft our own objects to manage calling our API. 135 00:08:44,610 --> 00:08:48,490 Remember, Spark does not come with this out of the box yet, maybe it will. 136 00:08:48,490 --> 00:08:52,530 So we'll need a way to test requests and responses. 137 00:08:52,530 --> 00:08:54,310 So why don't we start with the response first? 138 00:08:54,310 --> 00:08:57,020 I think that's probably the most clear one that we can do. 139 00:08:57,020 --> 00:09:00,740 Now we can add files in our testing bit over here right. 140 00:09:00,740 --> 00:09:01,760 So this is the main but 141 00:09:01,760 --> 00:09:05,030 if we come down here in the testing we can add a new class in here. 142 00:09:05,030 --> 00:09:11,830 So let's do that, let's do com.teamtreehouse.testing.ApiResponse, 143 00:09:11,830 --> 00:09:14,620 so this will be the response that comes back. 144 00:09:16,060 --> 00:09:22,324 And really all that we care about is, we want to know about the status, right? 145 00:09:22,324 --> 00:09:27,870 And we want to know about the body of it, what does the body from the response say. 146 00:09:30,070 --> 00:09:33,060 Don't really care about too many more headers do we. 147 00:09:33,060 --> 00:09:36,144 So, let's go ahead and 148 00:09:36,144 --> 00:09:41,541 generate a constructor, both of those, 149 00:09:41,541 --> 00:09:46,324 and let's generate some getters for 150 00:09:46,324 --> 00:09:50,039 both of those, there we go. 151 00:09:50,039 --> 00:09:53,343 You know what, these shouldn't change ever so let's not let anybody 152 00:09:53,343 --> 00:09:56,200 mess with the response, so we'll make these final as well. 153 00:09:57,390 --> 00:10:01,820 Okay, so after they're initialized they can't change, cool. 154 00:10:01,820 --> 00:10:06,365 All right, and now, we're at one of those places where there is quite a substantial 155 00:10:06,365 --> 00:10:08,170 amount of finicky code to write. 156 00:10:08,170 --> 00:10:11,050 It's a bit out of scope, but I want you to feel like you can do this. 157 00:10:11,050 --> 00:10:12,630 There's nothing magic here. 158 00:10:12,630 --> 00:10:14,830 I just kind of don't want to have you watch me type. 159 00:10:14,830 --> 00:10:18,080 So let's do this, in the teacher's notes, there is a link to some code, 160 00:10:18,080 --> 00:10:19,830 and you should go grab it. 161 00:10:19,830 --> 00:10:22,080 And what we're gonna do is we'll make a new file right in here. 162 00:10:23,760 --> 00:10:27,480 We'll make a new Java class and we're gonna call it ApiClient. 163 00:10:29,600 --> 00:10:34,430 And from here I want you to just copy the code and 164 00:10:34,430 --> 00:10:36,720 paste it in and we'll walk through it. 165 00:10:36,720 --> 00:10:39,570 All right, so I've got it copied and I'm gonna paste it. 166 00:10:39,570 --> 00:10:42,070 Okay, so let's walk this code. 167 00:10:42,070 --> 00:10:45,080 So when we're creating our server, what you do is you pass it in. 168 00:10:45,080 --> 00:10:47,160 And that's gonna be like our local host and our port. 169 00:10:47,160 --> 00:10:48,410 We'll do that when we create it up. 170 00:10:49,520 --> 00:10:54,990 And this is an overloaded method because we are not pulling in the body. 171 00:10:54,990 --> 00:10:56,770 I'm gonna close this so we have more. 172 00:10:56,770 --> 00:11:00,720 So we're not, you don't always wanna push in the body, right. 173 00:11:00,720 --> 00:11:02,670 The body is only for posts, usually. 174 00:11:04,050 --> 00:11:06,750 So this request here is the chunky bit of code. 175 00:11:06,750 --> 00:11:07,440 So here we go. 176 00:11:07,440 --> 00:11:12,790 So URL comes form the Java.io package, and here we're just going to build it, right? 177 00:11:12,790 --> 00:11:13,890 We're gonna build the URL. 178 00:11:13,890 --> 00:11:16,870 We're gonna concatenate the server that we know, and 179 00:11:16,870 --> 00:11:19,890 we're gonna take the URI that was passed in here. 180 00:11:19,890 --> 00:11:21,440 So that's /courses, right? 181 00:11:22,710 --> 00:11:27,840 And we're gonna open up a new connection, okay? 182 00:11:27,840 --> 00:11:31,930 And the way that connections work is you open them and then you set things on them, 183 00:11:31,930 --> 00:11:34,090 and then you call connect. 184 00:11:34,090 --> 00:11:39,080 So, we are going to open from the URL and create a new connection. 185 00:11:39,080 --> 00:11:40,970 We're gonna say that it's a post or a get. 186 00:11:40,970 --> 00:11:44,030 We're gonna tell it that no matter what we're setting this header here, 187 00:11:44,030 --> 00:11:46,570 we're setting that the content type is application json. 188 00:11:47,570 --> 00:11:50,440 And then if we have passed in the request body, 189 00:11:50,440 --> 00:11:54,210 we need to let the connection know that it needs to do output. 190 00:11:56,350 --> 00:11:57,790 It's a little wacky what you're doing here. 191 00:11:57,790 --> 00:12:02,220 So then, what we do is we open up a connection stream and we're 192 00:12:02,220 --> 00:12:05,640 going to put it in the try with block there, so it will close when it's done. 193 00:12:05,640 --> 00:12:09,190 And we write out to it, just in case there's any unicode characters, 194 00:12:09,190 --> 00:12:11,460 we want to write out of all the bytes there, so 195 00:12:11,460 --> 00:12:14,890 that we can get umlauts and accents and all those things. 196 00:12:17,020 --> 00:12:20,100 This line here actually makes the connection happen. 197 00:12:20,100 --> 00:12:24,930 And then what happens is we'll get back either an input stream or an error stream. 198 00:12:24,930 --> 00:12:27,490 So remember this is using a ternary operator. 199 00:12:27,490 --> 00:12:29,541 So it's saying if this is true, 200 00:12:29,541 --> 00:12:32,330 return the input stream, otherwise return an error stream. 201 00:12:32,330 --> 00:12:36,880 And what this is here is saying anything with a status code 202 00:12:36,880 --> 00:12:39,300 that is less than 400 is good to go. 203 00:12:39,300 --> 00:12:40,520 That's a good thing. 204 00:12:40,520 --> 00:12:42,070 Anything above 400 is an error. 205 00:12:42,070 --> 00:12:43,370 Remember that from HTTP? 206 00:12:44,680 --> 00:12:47,460 IOUtils here comes from Spark and 207 00:12:47,460 --> 00:12:50,760 it's going to take our stream and turn it into the string that we need. 208 00:12:50,760 --> 00:12:54,370 And then, of course, we're going to make one of those API Responses. 209 00:12:54,370 --> 00:12:56,740 And return it back. 210 00:12:56,740 --> 00:12:57,470 Whew! 211 00:12:57,470 --> 00:13:01,330 And then if anything goes wrong, we'll kick up a RuntimeException so 212 00:13:01,330 --> 00:13:02,360 that the test can catch it. 213 00:13:03,670 --> 00:13:06,220 There we go. Let's see. 214 00:13:06,220 --> 00:13:10,370 It looks like I forgot to paste the last trailing to close the client there. 215 00:13:10,370 --> 00:13:14,120 Okay, so let me know what you think about this approach of 216 00:13:14,120 --> 00:13:17,080 pasting versus slogging through writing this code. 217 00:13:17,080 --> 00:13:18,930 But the good news is this is written. 218 00:13:18,930 --> 00:13:21,110 Okay so we can use this now, right? 219 00:13:21,110 --> 00:13:24,820 So why don't we make it available to all of our tests, right? 220 00:13:24,820 --> 00:13:26,766 So we should put that in the before here, right? 221 00:13:26,766 --> 00:13:33,852 So we'll go ahead and we'll say client = new ApiClient and 222 00:13:33,852 --> 00:13:39,030 we're gonna pass in http://localhost, 223 00:13:39,030 --> 00:13:44,356 and once again we're gonna use our constant. 224 00:13:44,356 --> 00:13:47,540 Cool, so, client, we need to make a field for this guy. 225 00:13:49,200 --> 00:13:52,640 Create a field client and we have an ApiClient that we can use. 226 00:13:53,880 --> 00:13:57,776 Phew, right, so let's go generate a test. 227 00:13:57,776 --> 00:14:02,378 So, let's make sure that when we create a new course that it returns 228 00:14:02,378 --> 00:14:03,766 the proper status. 229 00:14:03,766 --> 00:14:06,956 So we'll make a new test and 230 00:14:06,956 --> 00:14:13,083 we will say addingCoursesReturnsCreatedStatus. 231 00:14:13,083 --> 00:14:16,431 And we saw in postman that this is working, but if we write a test for this, 232 00:14:16,431 --> 00:14:18,656 we'll always know that it's working, right? 233 00:14:18,656 --> 00:14:22,839 So writing JSON strings is a bit of a bummer, so 234 00:14:22,839 --> 00:14:29,940 I typically like to make a map and then turn that into JSON using our buddy GSON. 235 00:14:31,410 --> 00:14:35,839 So we're gonna make a new HashMap, and 236 00:14:35,839 --> 00:14:41,426 that is going to have some tests, put the values in there. 237 00:14:41,426 --> 00:14:46,542 So we will do Tests and, I forgot to do values.put and 238 00:14:46,542 --> 00:14:50,083 we want to put those values in there. 239 00:14:52,943 --> 00:14:57,463 And we will scroll up a bit here and we will say values.put. 240 00:14:57,463 --> 00:15:02,770 And we'll put in url and we'll give it our famous URL. 241 00:15:02,770 --> 00:15:05,690 We start doing more of these, we can always move this around. 242 00:15:05,690 --> 00:15:11,280 So now we have prepared, arranged our values, and we're gonna act. 243 00:15:11,280 --> 00:15:15,190 We're gonna say ApiResponse, and 244 00:15:15,190 --> 00:15:19,410 we'll get back a response object, and we'll say client.request, 245 00:15:19,410 --> 00:15:23,610 and this is the thing that we just wrote, we want to post that's method. 246 00:15:23,610 --> 00:15:26,450 The URI is courses, and 247 00:15:26,450 --> 00:15:31,765 the body is going to be a gson.toJson(values), 248 00:15:31,765 --> 00:15:36,840 and of course it doesn't know what gson is because we haven't talked about that yet. 249 00:15:36,840 --> 00:15:41,528 So let's go ahead and we will say gson = new Gson();. 250 00:15:44,608 --> 00:15:50,508 So it is a JSON and we need to make a field for that. 251 00:15:50,508 --> 00:15:58,320 There we go. 252 00:15:58,320 --> 00:16:06,536 We will now check that 201 is returned from our status. 253 00:16:12,096 --> 00:16:13,830 Here we go, what do you think, is it going to work? 254 00:16:15,070 --> 00:16:17,140 Let's make sure. 255 00:16:17,140 --> 00:16:19,725 So we will switch to All in course-reviews, 256 00:16:19,725 --> 00:16:21,430 this is being a test for that. 257 00:16:21,430 --> 00:16:22,640 And we will go run. 258 00:16:25,300 --> 00:16:28,410 And our API test fails. 259 00:16:28,410 --> 00:16:32,206 No initial, need to specify a class name or system property. 260 00:16:35,722 --> 00:16:36,910 I think I forgot. 261 00:16:39,430 --> 00:16:42,040 And this Sql2o, I forgot the username and password. 262 00:16:42,040 --> 00:16:46,080 That is such a confusing API that it doesn't, I always forget that. 263 00:16:46,080 --> 00:16:46,750 I apologize. 264 00:16:46,750 --> 00:16:50,310 That's the error that happens when you do that, just so you know. 265 00:16:50,310 --> 00:16:52,240 I have now done that twice. 266 00:16:52,240 --> 00:16:53,630 Sorry about that. 267 00:16:53,630 --> 00:16:54,590 Learn from your mistakes. 268 00:16:56,320 --> 00:16:57,030 There we go. 269 00:16:57,030 --> 00:16:58,660 So here it is. 270 00:16:58,660 --> 00:16:59,770 It worked. 271 00:16:59,770 --> 00:17:00,270 Awesome. 272 00:17:01,430 --> 00:17:04,810 So what else can we test now that we have a valid test? 273 00:17:04,810 --> 00:17:05,970 So we need to get a course in place. 274 00:17:05,970 --> 00:17:07,380 So let's go ahead and 275 00:17:07,380 --> 00:17:12,880 let's copy our course from the other test that we have in place. 276 00:17:12,880 --> 00:17:14,789 Pull up that new course. 277 00:17:16,020 --> 00:17:20,834 So, over here, in courses, if we come in the DAO, and 278 00:17:20,834 --> 00:17:26,297 we come in this DAO test, we will copy this new course method. 279 00:17:28,597 --> 00:17:30,413 Now, if we end up doing this too much more, 280 00:17:30,413 --> 00:17:32,810 we might wanna think about putting this elsewhere. 281 00:17:32,810 --> 00:17:37,630 So, we'll add a new, and that creates a course. 282 00:17:37,630 --> 00:17:38,726 And let's add a new test now. 283 00:17:38,726 --> 00:17:42,927 So we're gonna test that courses can be accessed by ID, okay? 284 00:17:44,667 --> 00:17:49,865 So do a new test method and we'll say 285 00:17:49,865 --> 00:17:56,806 just like we said coursesCanBeAccessedById. 286 00:18:00,697 --> 00:18:08,836 All right, so we'll make Course course = newTestCourse(); and 287 00:18:08,836 --> 00:18:14,320 we will add it, courseDao.add(course). 288 00:18:17,267 --> 00:18:19,027 And we need to make a new courseDao, don't we? 289 00:18:22,776 --> 00:18:31,319 So we will do courseDao = new Sql2oCourseDao. 290 00:18:31,319 --> 00:18:33,340 And it takes a sql2o. 291 00:18:34,860 --> 00:18:36,767 There we go, and we'll make this a field. 292 00:18:42,387 --> 00:18:43,706 Cool. 293 00:18:43,706 --> 00:18:47,434 So now we have an added course in our test, and let's go hit and 294 00:18:47,434 --> 00:18:49,167 make sure that we can get it. 295 00:18:49,167 --> 00:18:55,784 So we'll do an ApiResponse res = client.request. 296 00:18:55,784 --> 00:19:00,490 We're gonna do a GET this time and 297 00:19:00,490 --> 00:19:05,877 we are going to get back /courses/. 298 00:19:05,877 --> 00:19:11,385 Let's do this on the next line "/courses/" + course.getId(). 299 00:19:11,385 --> 00:19:16,630 So this is where you're using that method. 300 00:19:16,630 --> 00:19:21,790 And we're going to pull back from gson, let it do the heavy lifting. 301 00:19:21,790 --> 00:19:28,237 We're gonna retrieved back from the body there, or gson.fromJson. 302 00:19:28,237 --> 00:19:32,911 So the body that is set in the response there, getBody, 303 00:19:32,911 --> 00:19:36,897 should be able to populate our Course.class. 304 00:19:36,897 --> 00:19:41,163 Then what we'll do when we assert, we will assert that 305 00:19:41,163 --> 00:19:46,100 basically those are the same thing using the equality method. 306 00:19:46,100 --> 00:19:49,950 So we're expecting the course and retrieved is what we're checking. 307 00:19:49,950 --> 00:19:51,490 So we'll see if those are both the same. 308 00:19:55,350 --> 00:19:56,090 There we go. 309 00:19:57,930 --> 00:20:02,050 All right so we know that that worked too. 310 00:20:02,050 --> 00:20:03,640 Awesome. So both of those are working, 311 00:20:03,640 --> 00:20:06,890 so let's do one final test. 312 00:20:06,890 --> 00:20:12,547 Let's see what happens when we say missing course 313 00:20:15,327 --> 00:20:21,788 MissingCoursesReturnNotFoundStatus, right? 314 00:20:21,788 --> 00:20:24,000 So remember that was the 404 thing we did. 315 00:20:24,000 --> 00:20:28,920 So we'll just go ahead and get a response. 316 00:20:28,920 --> 00:20:31,820 We'll act right away because we don't care if there's anything out there. 317 00:20:31,820 --> 00:20:37,009 And we'll say request GET And 318 00:20:37,009 --> 00:20:40,430 we will just look for courses 42. 319 00:20:40,430 --> 00:20:46,740 And that should return a 404, we know that it doesn't. 320 00:20:46,740 --> 00:20:51,300 But let's go ahead and we'll write a test that proves that it doesn't. 321 00:20:51,300 --> 00:20:53,390 And then once we fix it, it will always work. 322 00:20:53,390 --> 00:20:59,090 Okay, so let's run, we got a red error. 323 00:20:59,090 --> 00:21:01,230 Expected 404 but got 200. 324 00:21:01,230 --> 00:21:02,960 Let's fix that. 325 00:21:02,960 --> 00:21:04,550 >> Now that we got our testing all set up, 326 00:21:04,550 --> 00:21:08,080 we can start to feel better about the validity of our API. 327 00:21:08,080 --> 00:21:10,620 Now, I realize that was intense. 328 00:21:10,620 --> 00:21:13,280 And most frameworks have that sort of testing built in. 329 00:21:13,280 --> 00:21:18,180 The good news here is, we are most of the way to writing a fairly generic way of 330 00:21:18,180 --> 00:21:20,330 functionally testing Spark applications. 331 00:21:20,330 --> 00:21:24,230 We could, in fact, extract that and refactor it into an open source project so 332 00:21:24,230 --> 00:21:26,450 that others wouldn't have to go through that pain, 333 00:21:26,450 --> 00:21:29,410 as well as they could extend and improve it. 334 00:21:29,410 --> 00:21:30,820 Now another important thing to we test, 335 00:21:30,820 --> 00:21:33,950 which we won't have time to get into here, is load testing. 336 00:21:33,950 --> 00:21:36,490 Since you're publishing your API to the public and 337 00:21:36,490 --> 00:21:40,270 anyone could be using it, you wanna know how much load it can take. 338 00:21:40,270 --> 00:21:44,040 Spark does an amazing job of handling many connections at once, but 339 00:21:44,040 --> 00:21:47,340 you really should see where it falls over and can no longer take care of requests. 340 00:21:48,510 --> 00:21:49,120 As you saw, 341 00:21:49,120 --> 00:21:53,100 we're getting super close to having a really nice API that we can iterate on. 342 00:21:53,100 --> 00:21:56,330 I think we should really fix that failing test. 343 00:21:56,330 --> 00:21:57,970 And make sure that when an error happens, 344 00:21:57,970 --> 00:22:03,250 we send the correct error message and HTTP status code from our API. 345 00:22:03,250 --> 00:22:04,580 Let's go turn that red to green.