#8 Intro to Swift Unit Testing

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Thanks

๐Ÿ‘๏ธŽ︎ 1 ๐Ÿ‘ค๏ธŽ︎ u/pasta_gurl ๐Ÿ“…๏ธŽ︎ Nov 10 2020 ๐Ÿ—ซ︎ replies
Captions
hello everyone and welcome back a big part of being a professional developer is knowing how to write automated unit tests and in this section you're going to learn exactly how to do that we're going to start off by looking at what unit tests are and what makes them so valuable you'll then learn how to add unit tests to an existing project we'll then dive in and look at some really good examples of what makes a good unit test and what doesn't and then finally you're going to learn how to write some really good testable code let's start with a simple explanation of what a unit test is and how they work unit tests are small method level tests developers right to prove to themselves that their code is actually working here's a simple example here we have a simple structure a user view model and we can test or validate our logic inside the view model by writing an automated test for example here we can instantiate the user view model pass in some users and then verify that when we call the has user's computed property this returns true we can run a unit test like this by clicking on the green arrow on the left and if all goes well that test will run we'll get back some positive feedback and voila we've proven to ourselves that our code actually works now don't let the simplicity of this test rule you we can actually test a really complex logic and get into some really hard places in code all through unit tests and the advantages that come with doing this are numerous for one they give you instant feedback when you make changes to your code and a unit test breaks you know about that instantly not three weeks later after you've rolled into production second unit tests dramatically lower the cost of regression testing instead of having to retest everything every time we pump out a new release we can save ourselves a lot of time and money by automating this really easy stuff so we've got more time to test the complicated stuff thirdly they greatly reduce debugging time when a unit test fails you know exactly where the problem is no more firing up the debugger and stepping through the thousands of line of code searching for that offending piece of code unit tests cut through the fog like a laser and show you exactly where your problem is and fourthly they let you deploy with confidence it just feels good rolling into production knowing you have a suite of automated tests backing you up they're not foolproof but they can free you up to test the more interesting complicated parts of your system and not retest the really really simple stuff if it helps think of unit tests like this unit tests can be your armor that you dawn before riding into battle they become a form of executable spec that lives forever in your code and they protect you from missiles real and imaginary dragons and most importantly ourselves so let's jump back now to the weatherly app and see what unit test we could write there to improve the overall quality of our code okay so before we can actually add any unit test to our project we first need to configure our project to run unit tests and if this was a brand new project that would be really easy we'd simply go in select app and then include this little check mark down here called include unit tests so then if we created our project something with a name like this and saved it our project would be configured and good to go with unit tests already added of course we don't have that so we're going to have to add our unit tests manually let me show you how to do that to an existing project that doesn't already have unit tests in there okay so unit tests and xcode run as their own target which means we're going to have to add a new target to our project in order to run our unit test but fortunately that's not too hard we can do it just like this if you click on your project name up here you'll see the lists of targets we currently have we just have one which currently runs our app the weatherly app we're going to add a new one down here by clicking on the plus sign for added target and then in here simply type the word unit and you should see a unit testing bundle option appear click next select that go ahead and select the default name that it gives you or you can just call them unit tests if you like click finish and those will then be added to a project and you will now see a new target here representing our unit test now we can open up our new target here this is where we're going to write all of our tests and they're kind enough to give us one out of the box this is a standard default test that comes with any new test target and in here you can see the basic anatomy of unit test all unit tests are classes that extend the xtc unit test case this is a class we inherit from they give us some routines for example this setup with error and teardown sometimes when we're writing unit tests we want to run the same code for each test that's run to kind of give us a clean slate as we're running we might make use of that later but we don't really need it right now here's an example test where you could put your sample test code the format here is to begin your test with the name test followed by whatever it is you'd like to test and this is a special kind of test down here this is called the performance test this isn't one i actually use very often and i just i tend not to use it but it could be used to measure the performance of your app and make sure your app's not going either too long or suffering from a big change that you might have recently made now what you and i are going to do is we're going to write a unit test for the json parsing that takes place in our weather service specifically way down here where we parse the json this is something that's a really good line to test because json person you know things can go wrong so if we can write a unit test that verifies we can bring some json in parse it correctly using decodable that would be a great unit test unfortunately we've already got a playground which kind of sets us up really nicely for that this is the parsing weather json playground this is something we created just when we're initially testing our parsing and here you can see some json that we want to parse in the app here you can see how we set up our decodables these are the objects that decode the json and when we run it down here we verify that we can convert that json into a weather data object and finally pull the results out like this so let's see if we can't write a unit test very similar to this and verify that we can indeed parse the incoming json okay let's start by going over to our new test target here let's go command n and let's add a new unit test case here so this option is already selected for me if it's not just navigate to where you can see unit test case class click next and let's go ahead and give it a name usually we map our tests one to one with the classes that we're testing in this case because it's the weather data struct that we're testing i'm going to go ahead and call this weather data test and just leave all these options here these are all fine we'll click next and we'll accept wherever it wants to stick it for us which is in our weather target here and then you'll see a new class come down here already set up and configured just like the ones we typically get when we create a new test project let's go ahead and just clear out most of what's in here we're going to start with a clean slate let's get rid of all this and you can see it's already set up for us to extend from test case and in here this is where we're going to write our test code to basically test and verify that we can do our json parsing now you may be wondering what exactly here do we want to test things we typically like to test when unit testing are first of all the happy path or the expected results so we're going to write a test in here that verifies we can indeed parse some incoming json but other things that are also really good candidates for unit tests include things like edge cases boundary conditions basic logic inner app you can think of it you can test it and that's really the spirit of unit testing if you've got a question about your code go ahead and write a test for it now to be clear the goal here isn't 100 test coverage it's way better to have 10 20 30 test coverage covered by a really good suite of tests so don't worry about testing everything just start with what's really obvious and then any other questions you've got we can add to the test but let's start with the happy path which for us is just going to be taking the json we decoded in our playground and let's just see if we can take this and have it decode properly in our test so we're going to start by first of all giving this a decent test name and because we're just simply testing that we can parse the weather why don't we call this test can parse weather and in there let's just drop in that string that we want to parse just like this so we're just going to embed the json right in here as a multi-line string literal and down here we're just going to add the code that actually has the parsing for us which for us is just going to be this now i know what you're thinking hey we've got a try in here and aren't tries dangerous this would really blow up our app and you're absolutely right it would in unit test however it's okay to be a little bit more aggressive and go ahead and use things like tries and bangs if the test builds up that's okay we want to know right away we want that feedback very quickly so in this case i'm going to go ahead and use the bang now you'll see a complaining here it doesn't know what our weather data is or in other words our weather data which lives up here in the model isn't in scope yet for the tests so how do we fix that well the first step would be to obviously just import our weatherly 2 module like this and see if that makes that go away and hopefully it will i'll just do a command b to give it a kick and it does but it's still complaining it still can't find our weather data even though we're importing the project here and the reason for that has to do with the scoping given to our target up here for our app all of the classes you see defined up here in our main weatherly target they have a default internal scope which means they can be seen within this whether to target but we want to test it down here in a separate target where our unit tests live so even though we've imported it that's not sufficient for us to be able to run our tests fortunately the good people of apple have thought of this for us and they've given us a way to take the internal scoping of our classes here and expanded something akin to almost being public and what we can do is we can use this test attribute called testable which will take these classes expose them for us in our test target so now we can come down here and actually use them in our test case okay now comes the fun part we've imported our json we've run our code now we just want to make some tests to prove that it's working and for us we're going to be doing that with the xc assert command this function as you can see has a whole bunch of different ways that we can actually assert things for whatever it is we're testing we can assert true and just put expressions into that method to verify that things are true we can check for nils we can check for false we can check for equal and in our case this equals going to be really handy what we'd like to do is verify that when we parse our json and get back our weather data we can indeed pull out temp which the temperature we want here and also our weather data name which is the city that we're getting the weather for here and of course we could grab and parse these other ones these are just the two that we're using right now so once we've got our assertions written all we get to do now is the fun part of running this so there's a couple ways we can run it one if you've compiled this you'll see a little block here that comes up with an arrow you can simply click this arrow here this will go ahead and run this individual unit test this is going to fire up the simulator the simulator is needed when we run the test and if all goes well you'll get a nice green checkbox here if we had multiple tests we had a whole suite here say we had five or ten tests in here the other way to do it is to go command u that will run all the tests in the suite and you'll get a nice output here also for the entire class now just to get you in the game a little bit here why don't we see if you can actually write two more assertions see if you can grab the id and description from weather and add two more assertions down here to just verify that we can indeed parse and read these from this incoming json go ahead give that a try and then we'll do it together after okay good luck okay so how did that go hopefully it wasn't too bad getting the id and the description is going to be very similar to these assertions that we wrote for the temperature and the city name first we're just going to change our expected values instead of a temperature of 10.58 we're going to expect an id of 804 and if we remember where that comes from let's open up the weather data file i'm going to do that showing you a different way of opening a file let's go shift command o look for our weather data object here hit enter and that'll just take us there and there we can see that the weather is actually an array of weathers there could be multiple weathers coming at us that's just the way this api is written if i go command control command back arrow i can go back here so in order to get this id i first need to grab it from this array and then grab the id and for now because this is unit test this is okay i'm just going to grab the first element and assume that there's a weather object in there so i'm just going to go weatherdata.weather i'm going to grab the first element and then grab the id likewise to detect that our description is for over class clouds let's come down here and just change our expectation to be over cast clouds we'll do the same thing we'll come in here and grab the weather we'll grab the first element of course here it won't be the name it'll be description and if we run that i'm going to go command u hopefully we will see that we get a green arrow there and voila our unit test passed that's great so we've got great confidence now that we're able to parse json we've got some an example of how to do it in the happy path scenario let's see if you can write a test for the not so happy path scenario we just got news that sometimes this city name won't come back to us it can be blank and it would be nice if we had a unit test to verify that we can handle a blank city name see if you can write a brand new unit test to handle the case where city name is blank i'm going to just leave it at that i'm going to let you think about this for a little bit and just work through what you need to figure out and what you need to do in order to write a test that verifies we can handle blank city names okay good luck go ahead and give this one a try and we'll do it together after okay how did that go i was purposely a little bit vague because i wanted you to go through the motions of figuring out how to write a brand new unit test on your own before we do it together because when you're on professional projects you're going to be asked to write your own unit tests i want you to start thinking about how we name and organize these things but let's start by doing the simplest thing we can let's just take our entire unit test that we have here for the happy path and let's just copy it down here and modify it for what we need so in our case we're going to have we're going to modify the test data the json itself we know we need to handle this scenario this is what we want to test an empty city name which means our assertion down here is obviously going to have to change it won't be calgary anymore it'll be blank and we should also give this probably a little bit more of a descriptive name to explain what it is that's unique about this test so before our happy path name was test can parse weather but why don't we add a little bit more to it here tess can parse weather with empty city name so that's the variation everything else is the same and i probably don't need to test these things again because i know we can already read the data and read these other values from our happy our happy path scenario this is all we really want to test so i'm going to remove those other assertions and just leave this one here so with that let's see if we can run this now you can see the little arrow that i would normally click on here doesn't appear sometimes you just need to do a build in this case i just went command b to run it and then that little option appears here and if we run this now voila we'll see that we're able to handle that new test case and this is exactly what we want to do with unit tests whenever we get variations or slate deviations from what we expect we want to come in here and if we've got any questions just write a unit test for it now json being json i probably wouldn't have to write too many of these because a json payload is a pretty concrete contract in other words the backend team probably wouldn't change too many things like this but if i did have questions about things that could come back as blank or null or as different values don't hesitate to go ahead and write a unit test for it it's really good to remove that ambiguity and you've got the unit test to cover you now this is a great start this is really good for just testing little snippets of json verifying that we can decode them and using them as structs and objects in our apps but you can imagine sometimes the json can get pretty big for example here's the json for the full on calgary weather as you can see there's more elements in there and if you wanted to copy and paste that text into every test file and repeat our classes would start to get really really big so another neat trick or something that's convenient to do to help organize our json responses is actually add json as a file and then load those into our unit tests off disk let's take a look and see how to do that now the first thing we need to do is to create a test directory for where we'd like to stick our json test fixture files so let's go ahead and do that now i'm just going to go command o to bring up our explorer over here and let's go into our test section here and let's add a new group and let's call it fixtures this is where we're going to stick our json test data and what we need now is a file to stick that into so let's go ahead and create a new file here let's go command n and up here in the filter just type the word json and you'll get this geon jason file which is almost exactly what we want not quite but let's go ahead and use it let's click next let's give it a name something like weather and let's get rid of the geo portion here so it's just weather.json and there's here's a really important point not to miss make sure when it comes to the targets you select your test target here to basically say make this file be a member of the target we need that because we want to be able to load that off of disk and the only way they can do that is that if it's compiled in as part of a an asset here so make sure you select target and then go ahead and click create and it will just ask you if you want to use the extension.json even though the standard extension is g on json yes we'll use that json and voila will now have a json file that we can edit so now we're free to grab our json in its entirety and plunk that into the file so i'm going to grab everything here make sure you don't select any comments like this as that's not legitimate json we just want the json i'm going to come in here just copy and paste replacing what we have in there and now we've got a json file on disk that we'd like to read into our unit test so let's go back to our weatherly test the one we've been working with let's add a new test case down here something like test can parse whether via json file just just a name i picked just to show us how we can do this and reading in a json fixture like this is really a two-step process the first step is we need to get access and figure out what the path is under the hood to get to our json file here and we can do that like this this is using something called the bundle which is basically xcode's way of representing all the files bundled within this app and we're going to search the path for the name of our file weather along with its type json this is going to return a path string for us which shows us where on disk this actually lives now we can take a look at the contents of that if we want to print out this path like this i'm just going to print it out with a couple of carriage returns and if we run this now in our debug output we should see where on path it has found our weather json file which if we look at the console like this we can see that it did indeed print it out and here's the full path on disk it's going to be your name way down and xcode derived data that's where it compiled this asset and that's where it's finding it on disk so that's step one now that it's found this json file and we've got a path string to it we want to take the contents of that file and convert it into a string some json something we can parse so the next step is to do this we're going to take that path that we were passed in get the contents of the file using that path name and then have that come back to us basically as a string which we're just going to name json so we've got the path we've got our json now we're able to decode it and decoding it is exactly what we were doing before we're just going to take our json string convert it into some data and then use our json decoder to decode it using our weather data self on the data and hopefully get back some values like this so if we run this now we'll see that we got some errors and that's actually probably okay because it turns out that what was in our json file isn't 25.65 instead it's 10.73 so that's great the unit tests are working so we'll just go ahead and test change this to 1073 and then we can also see that we're not actually going to paris unfortunately we are here in calgary which is also very nice but that way we can verify that we're reading from disk and if we run this again this is how we can create fixtures on disk load them in and then read them as part of our unit tests which gets really really handy if you're doing a lot of json parsing or your json response is really big this is a way you can read and load them in hey everyone thank you for hanging out to the very end this concludes our weatherly app and hopefully you've got some good tools now that you can use to go out there and build your own applications leveraging a lot of the stuff we did here if you'd like to continue the journey do consider checking out my new book ios tutorial this is a completely free book i'm offering online and in there you'll find a actual physical write-up of the weatherly app we just built so this is something i've created because i know some people like reading text instead of watching videos it's just easier to parse and go through a book than video so if this is something you're interested in i'll leave a link to the book in the show notes do check it out and uh do give me some feedback this is something i'm working on i'm hoping to spread some more ideas through this book and if it's helpful i would love to hear about it well thank you so much for coming everyone i know that's been a long journey but uh hopefully you feel more empowered you can do even greater things with ios development so do come back do hit subscribe do hang out and we will see you next time okay take care we'll see you then bye-bye [Music]
Info
Channel: Swift Arcade
Views: 4,062
Rating: undefined out of 5
Keywords: swift, ios, iosdeveloper, softwaredeveloper
Id: ZVSy9oj-7O0
Channel Id: undefined
Length: 25min 55sec (1555 seconds)
Published: Mon Nov 09 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.