How to test SpringBoot Application and How to use Test Driven Development (TDD)? Tutorial - Part 2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome back to spring boot tutorial in the previous session we started building a spring boot application today we will be writing some test cases for our spring boot application okay so just to recap we started building a product service which had two endpoints products and products with prod id okay so testing why testing is important testing is very critical to give your production ready code with confidence because team size and as as the complexity of the application grows without automated tests you can't deliver or refactor your code with with with confidence right so how many types of of tests are over there so there are basically two main categories of tests one you can call unit test unit test means you are testing a very small part of your class or or your application i.e you know it could be a method level right it can be as granular as as method okay and that's that's why it's called unit you are testing a very small unit of your program the second category of testing could be the integration test again there are two parts of of integration testing one is where you are kind of limited uh or you are inside your application and you just want to test if one class can you know talk to another class okay say for example our rest controller can talk to dao okay so this is called internal integration testing second category could be the external integration testing where you want to test your application is able to talk to external systems such as database okay or maybe another service okay or another messaging channel right so the approach which we are going to take over here is going to be test driven development exactly so you heard of this term but we are going to actually use this particular approach to write our test so how does the the test driven development works and how is it really different from like you know calling maybe just writing the unit test there is no difference right however there is a just mindset difference over here let's first try to understand what is test driven development in the test driven development you have three basic parts you have red category you have green category and then you have refactoring what does that actually mean so red means you start here you start here at red okay you write a test basically you're saying thinking about what you want to develop okay then you start writing a test and then obviously test is going to fail then what you want to do is then you want to implement that particular method or functionality which is going to make this test pass okay so green means think about how to make your test pass once you've done that then you can focus on refactoring okay workable code how to improve it because once you have written a code and like no your your test is passing okay you have built a confidence that okay if i do my code refactoring if i like no change i don't know maybe just variable name or a little bit of logic inside it as long as your test is passing you you will be confident in your changes all right so this is what test driven development okay so you first write a test make it fail and then then then refactor it okay then make it green and then refactor it what i have seen in in my experience is it's not always possible to do like you know 100 percent tdt reason being you know sometime you need a basic uh you know implementation and then you can write the test and later on maybe in in future you can start writing test cases and then you can follow this approach so i try to follow some sort of hybrid approach and that's exactly what i'm going to do over here so let's jump back to our code so what we built in previous session we built this rest endpoint okay as far as spring is concerned there are basically three type of of of test one is called spring boot test what it does it launches internal server okay and it gonna give you all the environment you need uh you need to run a web-based application such as this this product controller and then you'll be automatically and then you'll be able to call these endpoints and verify okay you know if i call get products for example am i getting the right data if you call ad products are you able to like you know create create new data or not are you getting the right responses or not okay so that's what we're going to do um another type is called you know web mvc test what it does it kind of bypasses that that server startup but then you have to give a lot of mock implementation or stub implementation we're going to try that as well third would be like not the normal uh unit testing where you are taking a class okay and then you're testing a public method over there so i am going to start with testing our rest controller okay and for that i'm going to use spring boot spring boot test even before that what we like to do is we like to write a very simple vanilla test what it's simply going to do when your application you know when you're building your your code and when you're testing it it's simply gonna check all the dependencies are are over there like okay um are you able to build spring context yes or no so that kind of gives you the confidence that okay you know all the things are are working fine after that you know you can start adding more tests so without without further ado let's just create a very first uh test for our spring application itself okay so the shortcut in intellij is if you press command shift t okay uh over here somewhere yeah it's saying create new test so just click on that i'm going to use junit 5 to test my spring boot application okay you don't need anything you simply say okay yes let's add to our unit so the first thing you want to do is you want to decorate it with spring boot test very simple okay what is spring boot test let's just go to the documentation it's saying annotation that can be specified on a test class that runs spring boot based tests okay provides the following features over and above the regular spring test context framework these various things you can read the documentation right so as i said what we simply want to do is we don't want to like you know test any business logic over here we just want to check whether or not i am able to start my spring boot application so what you can simply do is you can just say public void load context just create a empty method and you have to decorate it with annotation called test okay so this is a junit 5 annotation which gonna start your application you can leave a little comment over here uh no impul needed as we are simply loading the context okay it's it's probably a good practice it's not a bad idea to having this method you know just just leaving uh like that so it's just simply gonna run and it's gonna make sure like you know your your application is loading and i'll show you like you know what it means by uh you know when we have some issues so we have written our very first uh it's kind of integration test you can call it right it's a application level integration test so let's just run it very simply run product uh application test and you will notice it's actually launching uh spring okay that's that's what you typically see when you start spring boot application right so as you can see it's where it's gone yeah it's it's basically starting a spring boot application it's saying this is the version 2.53 okay and blah blah blah all these active profiles um are running okay it's saying all good now what i can do is how do i make sure like you know this thing is always running like you know it's not just giving me any dumb answer right so what you can do is go back to your product controller if you remember the dependency injection which i was talking about last week okay or in the in the previous session so let's say i try to put something over here let's pick up something called i whatever came in my mind let's say what we can do is i just want to put something like database driver okay and i'm just going to call it foo [Music] what it simply means is we are expecting spring to find a beam called foo of type database driver over here this is not a compile time issue by the way okay as you can see it's it's so i intellij might be showing you that this is a compile issue it's it's not okay however this is a runtime problem so if if you had your your test written at least this test written if you try to run it you will see a problem it will say i can't find this particular bean can you see the load context failed even though we don't have any business logic inside my load context but still it's telling us that you know what the thing you specified over here i have no idea what you're talking about i could not find the implementation for this database driver class correct okay so that's what the problem is if you if you scroll down if i go to the load context uh over here it's saying fail to load blah blah blah it's saying set up request context if necessary yeah see over here saying error creating bean with name product controller okay of course this is our bean and somewhere over here it should say no qualifying bean of type database driver with the name i have given it is it is expecting so this is how you build your confidence okay now if you're just wondering is it is it not a compile-time issue i can simply say maven clean and i can say skip test yeah if i say skip test you will notice our code will compile successfully build a success so these type of things you can you can catch early in this stage right where your code is compiled and you're kind of trying to give it to your your customer and when they try to run it boom it failed but if you had this test you would not be able to build your code if i if i try to do now you know move and clean test install or even without uh install test is always going to run if you try to do that it the build will fail so let's say if you have a pipeline pipeline will complain saying look i i can't find it so catching errors earlier is is very very critical i hope you got the idea okay and you can see the benefit of having a just plain empty implementation because you are loading the context okay let's just come back to our product controller so how do we test our product controller let's clean this class let's write uh a test because we don't have a unit test so so tdd is not started just yet but let's say we are starting fresh so first thing what we can do is now we are testing our spring uh sorry product controller test using again spring boot test okay so as soon as i define spring boot test when i start my um application it will it will launch product controller uh in in internal server what spring has done they are very clever basically so because if i try to start my um application obviously it needs to launch you know internal server sometimes you can have a port clashes let's say like if it's internally using 8080 there is always a possibility like you know there might be some sort of port clash so what you can do is on the spring boot test you can define that my web environment is going to be random port okay you say web environment equal to random port let's just do a static import on that so we have a you know just nice and clean line over here so what you need to define is you say this is a spring boot test but you know when you start this application spring please give me the random port so question is i have given a random port over here but how do i consume inside another nice way of doing it is you can simply say at local server port private integer port so spring automatically is going to inject or provide the value of the port where it's starting the the application on this particular variable now we are good to start our application or our test development okay let's write very first test called public just don't forget to decorate it with test okay and it doesn't have to be public you can simply say void the the approach typically i like to take is like no i like to give my method names really descriptive so i can say given products okay get products endpoint should return products list clear enough we don't need to do any documentation so if anybody is reading it tomorrow they know exactly what we are talking about so we're saying given products list all right given products data get products endpoint should return products less perfect okay let's just build a base url over here so we kind of reuse it maybe if needed later on so what we want to do is we we are saying my application server is running on localhost but i don't know about the port so this is where the port is going to be handy so let's say plus port and what is our end point we have something called products okay let's just have a quick peek over here so we are saying we this is what we are trying to invoke slash products says slash products over here perfect now how do i now talk to my server okay you you need some sort of like you know api which can talk to this this base url correct so what spring has done they have given another very nice utility called test rest template it knows exactly how to talk to your server it knows like you know how to make a request get the response you know serialize dc realize all that type of good stuff so you simply call it rest template okay and we need to auto wire it we done the auto wiring over here now we are simply going to say this template get for entity there are several methods inside this utility the one i'm going to use it is called get for an entity why i need to do that because then i'll be able to specify my detail where i wanted to deserialize um the the data for me so i'm saying please go and talk to this base url and the data which i'm expecting from this controller is it's called product dto okay um interesting thing is like even though we are returning list but jason would basically you know kind of treats it as array so we have to simply say um array okay this is a nice and clean way if you wanted to still you know kind of put it into list etc there are some complicated ways you can search on google it there is a thing called um arguments or something okay but i i think this is just good enough for us so what you can do over here is you can simply say uh response entity it returns a response entity in and it's gonna be type product dto okay it's gonna be because that's what we are asking our rest template to return it oops so we are expecting a product dto array to be returned and let's call it response okay so we got our response back over here now let's start verifying our response so how do you do that there are some assertion methods okay inside unit 5 we are going to use that to verify our our response so we can use something called assert that response okay and it's asking where do you want to import i'm going to say import from org asset j dot core api dot is equals so let's just check the response get status code because http is going to return a status code so we are saying give me http status okay okay you can write 200 which is fine but i'm gonna use like you know um everything given by various uh utilities or or constant classes okay perfect so what we have done over here is we made a request to this this url now we are just verifying that my server is able to return 200 okay when i make the call perfect let's just run our test just in case if you are wondering like you know where this spring boot test and all these things came just remember when we export when we created our project on spring initializer it already had a dependency called spring boot starter test it has junit 5 okay it has all the you know assertion libraries all the dependencies are already part of your project so the only thing you hopefully you you have used starter sorry start dot spring dot io if not this is the dependency you need in your project all right so we have now written our very first test over here this is like a internal integration test let's just run it product controller test if everything good we should be having a green test over here beautiful okay so we got our test completed it's it got whatever we we asked it to let's just um enhance our test a little bit what we want to do is as a next step i am saying let's just check the the length of the the message right so let's just say uh get body so this class called response entity has something called get body and you can say dot length is equal to we can basically say is equal or greater is equal is greater than or is greater than or equal to two why why i have that just in case like now if we add new products so right now we have just added two products in our dto when we start application by default it it has two products right you remember that we added two products sony 65 and sony tv 55 and that's what is going to be returned over here so i'm simply saying check the body size it has two products okay if you re-run your test it should run real quick okay and it's gonna verify that yes you have two products now let's say everything is good tomorrow one of your team members decided to add a new product over here what will be the the side effect of it let's let's just verify it so if i take uh yeah sorry yeah this is one product this is the second product let's say somebody comes tomorrow they decided to add another tv over here called sony tv 75 price is maybe 3000 or something okay and if you try to run your test do you think it's still going to work it's still going to work reason being because we have asked for equal or 2 greater than or equal to 2. if we had used another method called just equal to it would have failed so there are ways like now if you really wanted to be strict like that or you are you're flexible because these type of things can be added as long as it's not changing the functionality right cool so if i run the test now it's still gonna work that was the reason i used this method called is greater than or equal to this is just a guide like no okay perfect now let's just try to do proper what you call uh test driven development okay how do we do that so what we have in our post method let's quickly copy and paste this thing and now let's start testing the other end point which is basically test and let's call it uh given given a new product okay post products you endpoint should add a new product should add a new product good okay so let's just write a very simple test first so we have localhost products that that's good you can define as a constant but let's just just keep it simple for now so what we want to do over here is we want to now use another method called post for entity okay so what we want to do is we are saying instead of get use post for entity base url is fine and over here what you need to pass you need to pass a product dto.class also you need to give let's say product samsung so this method called post four entities takes three parameters okay the base url your payload the you know you can pass the class and it's automatically going to serialize into json and as long as you can tell what is the type of the data you are passing so what we need to do is we need to create this local class called product samsung what i'm going to do is i'm going to do a little bit of cheating over here i'm going to go back to product detail and as you can see we already have this bean over here let's just quickly copy paste okay and and refactor as per our need so i'm going to simply copy paste this thing over here okay and let's say please give me a local variable and let's call that local variable product samsung okay because that's what we need to pass over here as you can see now obviously it it because we are creating a product if you remember from the previous video our product id is generated at server when you make a request that's the only thing you need to do okay good stuff over here so obviously it's not happy because we are not returning the the array over here okay remember whatever you pass over here will come as part of your response entity so that error is gone we can get rid of this for now okay when you make a disc make this call let's try to run this method okay and then we'll start doing the proper tdd okay at this point i know we are already you know 15 minutes into the into the call we haven't actually started doing the tdd but this is the point we will start doing the actual tdd okay good stuff so our product um was added into to the store and then this method is happy now let's say business says okay you know what i don't want http status okay instead i want http status called created remember 201 this is typically a server returns a successful uh right saying yes some sort of data has been created if you were just posting something but you are not expecting something you can return 200 to but because we are creating a new resource on the server instead of 200 which is just okay i like to return 201 now if i run this test what's going to happen it's going to fail why is it going to fail because server is still returning 200. so you diff this is the proper tdd you define your behavior you you make the changes okay make the test pass and then start refactoring so so first thing we want to do is we're going to come back to our method over here and we will first thing we will say you know what whenever a product is added let's store into a local variable introduce local variable let's let's call it uh created dto okay doesn't matter what it is but yeah reason why i have created dto because what i'm going to do is in my add product okay i am actually yeah i'm already returning the updated or new dto so we can now notify our clients over here i'm saying return response entity okay response entity and in the response entity what i like to return i would be saying give me a data response entity dot status of what we want created we want status created as well as we like to send this data to our body okay created created you obviously it's not happy because it's saying your return type is not matching so we just gonna stick our response type over here there we are so we following the the tdd approach we had a failing test now we done we made the changes okay forget about the refactoring for now but at least now we have write the code to make test pass okay let's run our test case hopefully it's gonna work hopefully it's gonna work perfect this is proper tdd you define the behavior then you write the test cases cool perfect okay so one more thing we can do is let's say you know just just reverting back if if i did not have this this body okay dot created or build i could have simply said build now let's say i forgot to basically you know write the response okay so at this point my test still should be working yeah perfect now let's say i said you know response dot get body and let's store the body to local variable called new dto okay if i start inspecting that and if i said assert that new dto dot new d2 is not null is not null okay let's say our our business requirement came and said like when i create a new resource i would like to return it immediately as well okay so if i do that now we are making a test failure first it should fail it's failing reason why it's filling because i'm not returning anything okay which means time to implement new behavior like that if i run the test because i have started returning the data now this test should pass perfect one more thing we can do is we can we can now start adding more and more behavior i can start saying assert equals okay there is another uh api assert equals the the product samsung dto which i gave you earlier get the the name of it okay just make sure that the new ttu which is getting has the same product id okay assert equals that okay and second thing you can say uh product names should be same so this message will be written when products are not same okay so let's say i write that okay this gives me the confidence now tomorrow if somebody decided if if i come over here let's say like no just to just to tell you how things can go bad let's say somebody tomorrow decide to say you know whenever you have a name what you like to do is maybe uh take the original name which was there product dot get name use suffix suffix with some something saying um i don't know my shop i'm just making up story i couldn't think of a better way so let's say somebody you know some some developer came in and and start messing up with names if i had my test cases and if i try to build my my application it would fail why would it fail because i have this this safeguard over here and my intelligence saying this method failed if i go to my test i should have a proper saying i expected it's saying product name should be same okay this is the message it's saying expected this but actually server is returning me this so there is something some something has to be fixed somewhere something has to be fixed which means either i should be fixing my test or i should be reverting back my unnecessary change so this is how you safeguard yourself against the unexpected errors by having proper test cases hope it makes sense all right that's that's beautiful stuff okay going back to our tdd slide you must be wondering what is refactoring here doing you can actually go over here and you can improve your code how can i improve code currently i'm kind of defining into a local variable but then suddenly i decided hang on i don't even have a need for local variable what you can simply do is you can just put it over here it's refactoring one way or another it is a refactoring okay if i run my unit test now or my integration local integration test i can refactor my code with the confidence that it's not going to break make sense perfect okay so i think we we have now uh covered how to write integration tests using spring boot okay uh by using a thing called spring boot test and this thing is annotation okay the second way um second thing which i i said earlier was like you know how how can i write unit test so this is integration test this is good but how can i test you know just this these two utilities so let's just write very simple unit tests very very simple unit test covering again command shift t is your best friend okay so let's just write uh test we don't have to decorate i hope with anything as long as you simply say test void given pre pop populated data okay uh what method we want to test let's close this class we don't need this this was all good get products we this is the method we are testing by the way right so we are saying get products should return a pr a product list we are not using any spring uh dependency etc we are just doing a pure unit test over here okay how do you do pure unit test you simply say okay look i am going to manage the life cycle of this class so you say product dow dow equal to new product dial if it was done by spring spring would have done all these things for us but we don't care now we are simply saying assert that okay dow dot get products dot size let's just import this class from import static yes from our core dot let's see what methods we have so what we can test is we can actually put something called is equal to two okay let's be very very strict saying okay just check when whenever this class gets initialized for the first time the size is two okay i'll tell you why i'm doing that so let's run this method hopefully it will work it did not it's saying expected to but was three sorry it should be three because the size of this product list is three okay so let's just say size three okay this method is done perfect so we managed to test that whenever i call this method called products it's gonna return a product list okay and then it has a size of three this is good now let's write the second test for add product okay how we can do that just copy paste okay and then say given a new product dto add product should add add should add and return dto with prod id okay so let's start with this very simple thing again you define dow you you can you can actually start with saying assert you know three that's good now let's just what we can do is we can again do a little cheating over here we can go back to oh not this one where is our controller test yeah over here remember we defined uh the is yeah this one let's just copy this thing paste over here let's say i'd like to add product samsung to my api so say dao dot add product for me please product samsung okay now it has edit let's just because it's returning a new dq as well let's just call it created dto so what i can check over here is i can check for few things i can check first of all created d2 is not null also created d2 has id okay another thing i can check is i can check when i call the get products again the size is not equal to three it's basically has incremented to four so let's do this thing first as soon as you have added a product if i call this method with three it's gonna fail instead i'm going to say it should be four the size of the list must be increased so let's just run this test good okay as you can see earlier it was three as soon as we added a product the size has become four perfect now let's start testing created dto so if i say assert that dow dot get uh just do one thing let's just hide this thing so we can do a proper you know a test driven development let's say this thing was not here and if i put a logic saying get assert that dao sorry no doubt assert that created created dto get product id is not null all right so if i do that this test is going to fail because when we send product samsung we did not have id we are expecting server to create that for me so now this this test will fail so what we can do now is it's saying oh expecting actual not to be null okay so this this line failed come back and now remove that and when we get the response back from server see our test is passing now so this is how you do test driven development you make it fail then you improve it okay so you make it pass and then later on you can do refactoring what refactoring can we do over here okay we want to get rid of this thing as well okay so this is a kind of refactoring isn't it also we can say let's define this into a constant okay actually we okay let's first make sure our test is still passing yeah let's say i want to do a refactoring that you know i as far as product id is concerned i'm kind of hard coding things p plus id id okay this is this is quite cumbersome like tomorrow if i have to change the logic i have to you know make make so many changes instead what i can do is i can extract this thing into a method i can say create id create and get id let's write this method called create id okay what this method is very simply going to do is it's going to say p plus id id now we can very safely replace this thing okay everywhere we we kind of had hard-coded our logic even over here see this is a kind of business logic right where we are creating the now we are relying on this method called create and get id it doesn't matter what what business logic is inside at least we managed to do a lot of refactoring over here if i run my test it should be passing see with confidence i can now make the changes all right i think we can finish this session over here one thing uh we can do is you don't have to run these tests individually okay you can you can right click over here and you can say run everything second thing you can do is which is basically let's say you have some sort of jenkins pipeline okay this is the command your pipeline will be running right install and automatically it's going to build your code run all the unit test cases as you can see okay the unit test case is running perfect build success yeah it just to show you it it ran all these tests okay it ran five zero failures okay um yeah okay i i hope uh you enjoyed this session in today's session we learned um you know how to write spring boot uh tests okay how we how we can test rest endpoints we also learned test driven development thanks for your time
Info
Channel: Saggu
Views: 345
Rating: undefined out of 5
Keywords: Java, Spring, Springboot, EIP, Tutorial, Code, TDD, Test Driven Development
Id: MRG6rm54lhA
Channel Id: undefined
Length: 42min 55sec (2575 seconds)
Published: Tue Aug 17 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.