How to Write Testable Code with Dependency Injection | Swift | Xcode | TDD

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys welcome to my channel i code i am pallav and today we are going to look at a very interesting topic that is dependency injection and how can it help in making our code testable it is one of the frequently asked interview questions and interviewers rephrase it in different ways like explain dependency injection what is inversion of control explain how can you write loosely coupled code how can you make your code testable etc so let's dive in and understand it first we will see what is inversion of control what is dependency injection and then we will write a test case using dependency injection to see it in action let's start people often confuse inversion of control with dependency injection inversion of control is a design principle which is achieved using dependency injection and what does inversion of control principle says it simply says that invert the flow of control in easy words we can say that create the dependencies first and then create the instance of the entity that will be using those dependencies and how that entity will get these dependencies so for that we can inject them through initializers setter methods protocols or some other way but the baseline is that the entities should not have dependencies as the concrete implementation instead they should be injected them from outside this helps us in following the single responsibility principle of the solid concept makes our code loosely coupled and eventually easily testable we will see that in a minute so for now you can consider this entity that is checkout view model it is having two dependencies shopping cart and payment methods it is also having one method that is make payments and that is its core responsibility so following the concept of inversion of control we should be removing the dependencies so what we can do is we can remove the shopping cart and payment methods outside the implementation of checkout v model and then the only responsibility of checkout view model will be make payments so we will be following the s principle here now comes the point that how it will get payment methods and shopping cart because it is dependent on them so for that we will be writing an initializer and through that initializer we will be injecting these two dependencies that is payment methods and shopping cart let's write the code for this assume that this is some e-commerce application in which i have this screen of shopping cart i am having two products here two guitars basically and this is the payable amount and from here i can make the payment and can proceed with my purchase so this is basically a checkout screen and i'm having this checkout v model in which i have an object of card that is my shopping cart and in the cart i have a dictionary for products in which i am having the products i mean the name of the product and the price associated to that and the method for getting the total payable amount the checkout model is having a method make payment which is using this method get payable amount and through this we will get the payable amount which will be used for making the web service call for completing the transaction for completing the purchase so basically this make payment method will be calling some web service for completing the purchase and for that it will be using the get payable amount method of the card and the card here is one of the properties of the checkout view model now the problem is that i don't want to pay the actual amount for testing purpose so here the amount is somewhere around 1 like 15 000 but i don't want to pay this and of course i understand that this is not the way this is not how it is done this is not how it is tested in a real project there are separate testing environments site uat pre-prod and all that for testing the purchase but that is not what i want to convey here what i mean is that i want to make the web service call here which is dependent on this card but i don't want that dependency to be inside in this checkout view model basically i want to provide some mock data so that i do not need to change the make payment implementation but i should be able to pass the mock data whatever i want now it is not possible here because checkout free model is dependent on cart and cart is one of its properties so i have no way to provide the mock data i have no way to change the amount of the card so what we can do here is that we can use dependency injection basically we can inject the card as one of the properties what i mean is instead of taking the cart object here inside the checkout view model we can pass it as one of the dependencies we can inject it through either initializer or some method and if we do that we will be able to change the data of the card so basically we will be able to provide the mock data that we need for testing now to do that the first thing that we need here is an initializer because through the initializer we will be injecting the dependencies so we need an initializer here and then we need a parameter for the card and instead of taking card as a type let's create a protocol for the card that should be say protocol card protocol and let's mention everything whatever there is in the card so it has a property for products and uh method for getting the payable amount so it should be say where products and the type here is a string double and we need to mention we get and set with the properties of the protocols and the second thing here is the get table amount so function get variable amount which will be returning a double and of course it is in the protocol so it cannot have implementation so now we have this protocol card protocol let's make our card confirm to this protocol cool and now instead of having the cart object here we can have the object of card protocol and take that as the parameter say card right protocol self dot card is equal to part so now in the checkout v model we will be receiving card as one of our dependencies and we are having that flexibility to change this object whenever we want so when we want to test it when we want to pass the mock data we will create a test card and we'll make it confirm to the card protocol then we will be able to change this implementation of get payable amount we can return 0 from here and because make payment method is using the get table amount method of the card it will get zero so the web service call will be made for the dummy data the mock data the entire implementation of this make payment method will remain as it is but it will work for our dummy data and we will be able to test the implementation of make payment without actual data or in fact without making any change in the checkout view model so let's go for it so here we want to test our checkout view model basically our make payment method but that is in the checkout view model so our suv object that that we call a system under test our suv object will be checkout view model and checkout view model needs a card for initialization so let's create a card and because this is for testing purpose so let's create a test card so what i can do here is that i can create a class say test card and this needs to confirm to the card protocol now because we are confirming to the card protocol we'll need to override the properties we need to confirm to the methods so it it has a property products let's initialize that with an empty dictionary and from the get payable amount we can simply return zero without writing any of the implementation of the get payable amount and now we have a test card so let's use it here i can create the object for test card and now our test method so let's say test my bad test make payment and here i can simply call the make payment method now this make payment method will be using the card or should i say the test card from which we are returning the amount as zero so let's try and test it so if i run this and in the console we can see that made payment of 0.0 so basically whatever this make payment method was doing it was not doing much for this demo but whatever we had in the implementation of make payment method has been executed and if you want to use those xc assert or those test conditions you can definitely do that you can change the implementation of the make payment as per your needs and then accordingly you can put the xcss here you can compare the results you can evaluate them but basically the point here was to explain that how can you use dependency injection in writing the test cases so basically we have changed the implementation of our checkout p model by using the card protocol now we are not using the actual card the actual amount the true data that it had instead we provided the mock data and then we are using it for testing so the test cases can be enhanced to any level you can mock the web service calls you can test the json parsing and you can do a lot of stuff well that is not the point for this video what i wanted to tell you was that how can we use dependency injection to make our code loosely coupled and it's not only important from the interviews point of view but it overall enhances the code quality makes it more manageable and it makes our lives easy so we should follow the practice of using dependency injection for writing manageable and easily testable code so that's pretty much for this video a new video comes out every weekend so you can consider subscribing to the channel let's write better code together happy coding and stay safe
Info
Channel: iCode
Views: 2,031
Rating: undefined out of 5
Keywords: dependency injection, test case, unit testing, iOS, swift, xcode, iCode, pallav, pallav trivedi, tdd, testable code, inversion of control, ioc, android, mobile app development, switui, iOS interview question
Id: w9I3Q_uG-6M
Channel Id: undefined
Length: 9min 47sec (587 seconds)
Published: Fri Jul 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.