S01E06: [TDD 🍅 5] Testing View Controllers in Swift

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey this is kayo and this is Mike from essential developer.com okay so we have the flow working we now have a bunch of options we can start thinking about this car thinking about the moldos because I don't like the questions and answers being just strings in for the results a dictionary might not be suitable or what we want or we can implement some UI and get some feedback exactly more reviews from our clients from our friends if you have a client I think the way to go here would be to have some UI yeah so we have a prototype they can play with but it's not the real game it's very mucked up hard-coded if you're in a team this development can continue independently a developer can continue working on the scoring as you said and another developer can work on the router implementation or the UI in parallel in parallel yeah yeah definitely as long as you have a contract between these modules as we do right now with a router for instance two separate entities can continue in parallel okay cool so we have a project already there is a prototype but since everything's are coded I think we should just start a new project okay okay let's create a quiz app and we want unit tests okay new project a lot of things I don't want right now so I can just get rid of it okay seems good let's see if I can Randi's oh you need to remove the main interface yes so from here I don't have a starboard anymore let me run this again okay boom empty application okay I think we should start with the question view controller as we had in our prototype where we show a header and a bunch of options you can select make sense let's start with the test yes so let's create a question view controller test no thank you we import actually tests and let's create our test case class and let's create our first tests well to test for controllers you need to load the view so it's in the red states you'll be rendered on screen and you need to start the view lifecycle exactly it's pretty much what would happen if they put on screen so we can start saying when we load that's how simple we have a header so it renders header text so I assume that the header text is gonna be the question yes okay she would say when question header text question hazard okay so let's create our assertion what do we want to happen is we're gonna have a system under test that's gonna be the view controller and we want a question had their label I think it's too long I will just call it header label okay dot text needs to be whatever we pass to it so in this case let's say q1 we need to load the view one way to do it is just to call the view here right why don't you just call viewdidload there well if you read the documentation of your controllers you shouldn't invoke viewdidload directly that's not the natural way of things happens to load of view there are some internal things that happens only when the views access the first time so should be a nice citizen it's better to just just follow a simulation right exactly so we need to create a suti and give it a question q1 that's it so that's great one question your controller here in or main target let's import you like it and let's create our class and that's a view controller and it has a initializer that gets question strings and we need to capture just somehow so neither I'd want this be accessible so let's make this private and let's make it a string well you should probably be a let I don't this changing maybe needs to change but so far it doesn't and well I have a compiler error here well it forces me to have the required initializer so maybe we should have a convenience initializer instead yeah this is UI kid madness here yeah the custom initializers but the convenience should do it convenience initializer so then I don't need this year but I need to call self-taught in it and then set my properties yes so what is happening here okay it needs to be a far I'm thinking to have default value also okay that's why and we need to have the label that we can add here I like to have these layout separated from the view controller logic so we could have a different class that sets up they had a label for you and layouts it or just a need you don't need to do it programmatic me okay let's create a field and we've used the same name as the class when you call in each it's gonna do the loading for you couple of things we need to do when you have any you need to set the fire on their class and set the field to whatever it needs to be okay and or header level right now I don't want to care about how it looks no layer is not part of the unit test maybe you're gonna have some UI tests for that but I think that's enough for now so control drag and we can create our header label week yes please boom there it is let's go back to our tests we have our header over class oh that's the phone in turn oh so our test tiger doesn't have access to it we can make it testable import squeeze up and that should do it so let's see the difference now that we're running the test with a simulator how long it's gonna take a lot well it wasn't that bad but let's say three to five times slower I think it's a lot more Emma but yeah that's pretty slow but okay let's make this very test pass now let's have a viewdidload we just need to set the header table don't text you be the question that's it okay okay that's all we need a second test here let's say we need to also show the options for answers right so this can be in a table view if we follow a prototype it's a table here I think it's fine to do that Princeton simple solution so start with 2-0 case okay with no option options renders zero options okay so now we need to give us some options let's say it's empty there are no options and we are going to load the view and we need to assert that table view number of rows is zero something like that yes so okay let's start with these options and it's an array of strings so far what else this is gonna break our first test so we need to add this here and let me comment this out and make sure it still works okay it works so we need a table view now and we can follow the same process for the header we track a table view to our mains view and we control drag it to our code and table view now we connect them back to the test for a test on the right method name okay I think it's in section zero yes let me run this test any passes we have passing tests and we have no implementation there's no other but is good you have it there because as we progress we might break it so let's carry on to the one option test you just copy and paste these so one option renders one option a one okay yeah and now this should be one let's run this should feel and it should fail and it does now we need to start thinking about this tape of your data source and who should be the tip of your data source isn't the view controller could be let's start with this then later source and we need to implement some methods now yes so table view number of rows is mandatory and we can return one to make the test pass but then we would break the know options exactly so right now we can just say options dot count but we still don't have an option variable so now it's time to have a private or options just like we have for questions and it needs to be an array of strings and you need the default value and I think empty is a reasonable default value yeah and we need now you have the other required method cell for row let's just return cell for now that's we're gonna get there it's mandatory you need to implement it we cannot return you it's not optional so we're gonna get there and it fails because our table view is not connected with the status verse yet we could do this in code or we could do it in the interface builder and since we are treating these I think it's fine to the interface builder less code it hides the annotation but yeah for now it's fine so I can get the tableview here and connect the data source to D files only I should let's run the test again hey and he does okay we could add a test to make sure that the table of your data source is the question of your controller but doing so will make your test a bit fragile because if you decide to refactor and have a different data source class a different implementation then it's gonna break that test and you're gonna have to go there and fix it actually what we want to do is just say the table view has it like it doesn't matter how it has like 1 or 2 or 0 rows what matters that it has it so it's easier later to refactor this and put this data source in a different object without breaking the test the test is still true it's you see yeah you guys the number of rows I want doesn't matter how doesn't matter who's providing that so write less tests in your test is more about what it does not how I think that's very important so let's carry on we could have the two options but I think we we're good here yeah same physical assertion there so that's finally think about this cell and the options is just a string rendered in a Cell so renders one option label yeah another thing we're not you next as to follow our convention here sorry I don't think we need to create any custom cells right now yes we don't have a layout yet so I don't wanna be putting any layout concern in my production called Orion test so I think it's fine for us to just test these with normal tape of yourself it has a text label Adri ok so if you have this a1 I want to make sure that I get a cell and he has the a1 rendered in there yes so let's do that let's get the cell at index so say that table field data sirs and that's optional we need to get table view you know we pass the su t dot table view cell or at index path put this in a variable let's call this cell and let's create an index path that's 0 in section 0 now we can test it or sell text label dot text is a 1 yeah it's exactly right what is wrong then that's an optional okay oh that's interesting it's optional because the data sources are talking you although this method returns a non-optional since there is an optional in the chain it's gonna return an option yep interesting let's run this test and I expect you fail ok right now we could just hard code a 1 here like we did before in the flow and then have an a - well I don't to be hard coding stuff anymore yeah you will probably don't do that and yes I'll probably not do that so what we can do here now you can create our cell then I can get the text label and get my options at index path row that's it timer is done huh perfect timing let's just see if we pass well that's optional optional yeah and I don't think that's gonna work because I need to give it a style let's see then my crash yeah it passes it's perfect timing for a tomato to end that's it about what we did so far so for me the interesting thing here is the separation of the layout it's one thing to test the behavior of the view controller and another thing how this view controller and it's up huge is gonna are gonna look like and final fascinating to be honest I know it looks stupid right now but I think it's gonna pay off later well if you look at the feel it does look stupid right but how important is this like we don't care about the layout right now we are testing the behavior of this controller and implementation of the sale data source and we even enable this implementation to move somewhere else without breaking any tests and I think that's very very important I expected to have like a nice UI at some point they I'd want to be breaking this code because of this new UI okay let's move to the next one [Music] you
Info
Channel: Essential Developer
Views: 7,762
Rating: undefined out of 5
Keywords: ios, swift, professionalism, pairing, ios development, ios engineering, ios app development, xcode, tdd, modular design, architecture, agile, advanced ios development, tvOS, macOS, watchOS, iphone, ipad, advanced swift, clean code, unit testing, testing, best practices, swift framework, pair programming, xctest, framework, swift 3, swift3, @escaping, closures, screencast, recursion, refactor, refactoring, course, advanced, UI, view controller, UIViewController, UITableView, table view, UIKit
Id: xD_Z4AA2eic
Channel Id: undefined
Length: 16min 5sec (965 seconds)
Published: Sun Mar 26 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.