How to start writing tests with Laravel - Testing models, controllers and notifications

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey guys I'm actually recording this after the video I just want to ask you to hit a like and click Subscribe if you want to help me force and I have a TDT newsletter where I also release the course because earlier and you can check it on the description and there's also my Twitter I don't post much but I might so that's it and let's here to the video so today I'm going to walk you guys through how I usually do my Testament so I have a fresh layer of install I am using 107 and I assume you already know the basics of TDD if you don't I suggest to check the testing page on the laravel documentation it's really good it's gonna give you some concepts but today is all about absolute testing so tests can be beneficial in several ways first of all it allows you to actually know what's going on with your code second of all it helps you maintain your code so let's see write a feature today and you didn't write a test if someone writes another code like one or two years later and it uses the same class or something it may break your previous code and you won't know if you did have a test it's going to show you if you did have a test you were going to know that so I'm going to leave those in the description some some reasons about why testing is important so we don't lose much time with the video so I already have sublime open here and let me just make this smaller I don't know how to do over here ok cool so the first thing I like to do is check the PHP unit XML file if we go down here we have some configuration that helps are just first of all we have this one here a TV connection laravel defaults use sequel I don't test and use an in-memory database this is really helpful as you don't actually need to have a database here in tests but I suggest changing this not going to cover this on this video it's not a really big issue feel of this as it is but if you are using an specific feature of either my sequel or Postgres you have to change this and if you are using another driver like you will also have to change this it's not gonna work then we have our app and which is the file it's test and we do have some sports stuff like second the queue connection to sync so we always run our jobs starting to male-male are Turay so we don't actually send emails and session driver and telescope so learn how ships with two folders here future tests and unit tests unit tests are supposed to be used on a single class like if you want to test a helper class who wrote a service something like this while future tests are supposed to test a bigger image of things so kind of like the whole request life cycle if you're testing a controller you are really writing a feature test now if you're writing a test for a model some people like to say this is not a unit test because the model interacts with several other classes and that you can search the database on unit tests I don't agree with this I think that's it it's fine to search the database after all it is there you have to test it so I would usually have tests for models and some services here and have controller tests here so we are going to write a course app so it's an app where people can subscribe to courses and courses are added by the staff so the first thing we got to do is to create the models we already have the user model we need to create the course model so let's go back here oops here let's run make model course and use the M flag to get a migration cool let's go back here let's go to the migration file so what do we need on the course it's a well we need a title and we need a description let's just go with this for now so subscription actually let's make that a string as it's not supposed to be big and make it knowable now let's go to the course table the course model sorry and create the fillable property we want the title the description two-syllable okay we already have that done so the first essay I want to write is that a user can subscribe to course so you generate s level provides a really nice command called make test so let's run it if we just write a test name let's see something like users can subscribe to courses test if we press the unit flag here is generating unit test if we don't pass anything it's going to regenerate a feature test so let's run it and here we go you'd already comes with an example let's get rid of it now there are a few ways to write a test case first of all it's using this notation so will you write a function a method and you say test something PHP unit is going to recognize this as a test if we write test something it's also going to recognize it that's s now what I like to do is write something like this it subscribes to a course and then we can add the test notation here and it's going to work now the first thing I do whenever I create a test file it's think of all the tests that I can think of obviously and right then I'm not going to actually write them but I'm just going to put them here so it subscribes to your course and it just not allow a user to subscribe sorry a subscribed user to subscribe again and the ones that I'm not going to write right now I'm going to mark them as incomplete and let me add the test notation here and this one I also want to send a notification so sends a notification now the other thing that I do right before I write anything it's full the database migrations trade or the database transactions what it does is it migrates everything it will enter tests and then it refreshes the database it's really really helpful so let's use it there are these migrations for tea you're good so when it's going to when it starts to run this one is going to migrate everything run your test and then refresh it at base so it's fresh on the second test right here now what do we need to test this we need a user and a course obviously and lerigot provides a very helpful feature called factories factories basically allow you to mass generate models imaginary records on the database and here's how you write a factor we say user factory user now if we want to generate multiple users we can pass a second argument here ah yeah we are not going to so let's just continue and we say create and we also need a course now let's try running this lets save Andrew bean future unit so it's failing unable to locate Factory of course we haven't created factor so let's write it make factory course factor and we feel if we go to database factors we see it here learn how already comes with the user factory so first we have to define the model so close and here we press the attributes it already comes with faker which is a random data generator so let's say title let's say that we want a fake sentence and scription let's say paragraph actually let's live that let's leave that as no so let's run this now well the task did not perform any assertions so PHP unit has this very helpful alerts whatever like to do sometimes is just jump and die some variables to check how things are going so we can see that we do have a record being generated now it's time to actually test this we need to simulate a request so how do we do this lera already provides this to us so response let's say that we want to make this request as if we were the user so acting us then we want to make a post request to a route called courses subscribe and fast of course and after we have the response we we want to make sure that we were redirected to horses show horse and we also want to make sure that the user is subscribed to the course so how can we do this um let's say we want to assert that it's true we're going to use two assertions very often also true and assert equals all certain equals is just making sure that a value is the same as the other so we want to say us are true and that the user you subscribe to course what's great the course now this is really nice whenever we are writing tests sometimes we stumble them things that require us to write another test so we don't have this method yet and we are going to write it but you're also going to write a test for it before we finish testing this one so let's run our code so root courses subscribes not defined well that's true we don't have the route so let's go through the routes file let's write a controller called subscribe to correspond troller let's say foes course subscribe named horses subscribe now let's run again or tests okay now we have another error so we don't have that action so we don't have any subscribe to course controller but it's each creator oh okay we don't have to invoke the method so what's writing we have a course being passed and let's jump the course just to check things we can see that the course isn't even best so I want to make sure it's redirecting okay now what we do in tests you know what the whole methodology is is that we write tests we run them they're going to give us a red which means they're not passing they're going to fail we write the simple code possible to make them pass and then we refactor always making sure that they are green now I don't like to take this to the extreme so what do you usually see on some some testing videos and stuff is that they are going to write something so we want to make sure it's resurrecting here so we could do something like interact rude courses sure of course now what they do is they're going to write them simples code possible even if it doesn't make much sense because right here we are not subscribing the user and go step by step and this is helpful in the beginning but you are going to quickly get tired of it so as you get more experienced you don't need it you already know what things are going on so it's easier for you and so you wouldn't do this but let's do this so let's run it so root courses show and not to fight the reason we do this when we are beginning is because the tests are going to give you a direction they're going to say you what you need to do so I was right now it's sexually telling us that we don't have that we're define it so let's create it let's create a controller so of course is controller well let's make it a resource let's just say we're resource of course this of course this controller let's run it oh sorry it's exactly it's redirect I'm sorry let's run it so call it's you and the funding method you subscribe to course now it's time to write another chest so let me clear this and let's make a unit test so make test of course test unit if we go here okay we have it now if you see you see that it's extending the PHP unit framework test case and the other one is actually using the illuminate I'm sorry the test test case those are a bit different when we allow a filler everyone it's actually loading the application and it allows us to you things like factories and do requests this stuff like that so I don't like using this one I prefer to use level one theoretically the test in the unites folder sure didn't have access to the application but as I said in the beginning I'm that's up to you this is not a hard bill it's not a rule at all and I prefer to have them here so let's import it test test case ok so the test that we want to do is it checks if a user is subscribed to a course and let's use vectors again so let's copy it from here let's import the classes okay now first thing we want to do is make sure that right now the user is not subscribed to the course so subscribe of course we could also do assertequals here so we could say whatever it doesn't really matter let's use assert false then we want to subscribe the user to a course so let's say user subscribe to course let's piss a class of course and then we want to make sure that the user is subscribe to the course now here's a little trick we already know that we're talking about relationships here and if we write any code that uses memory relationships if you don't know what it is it's let's say you have the courses relationship already if you do courses yet like this you are fetching the courses all the time every time that you run this so if you run this twice you're fetching the courses twice now if you run this Larry vu is going to fetch the public courses sar than in memory and if you run it again it's not going to do this it's just going to choose the collection that's already memory that's really really really important when you are testing so when we're testing something like this we've already checked it once if the user is subscribed to the course if we are doing this in a query that's fine it's not gonna going to give us any issues but if we are polling the courses and then checking if they are if the user is subscribed to researching course it's only going to fetch the courses once so what we were going to do is make sure that the user is subscribe to the course later and because we already fetched the courses this is going to show us false all the time because the courses are already in the model so what I suggest you do is and every time you do stuff like this that you are mutating the object not mutating in this case but that you are adding relationships adding anything that's related to a model is to refresh it right after so we subscribe to a user and now let's refresh it we can just call refresh wherever I was going to get us a new model instance a new if a fresh record and swap wait for us it's the same as doing user equals user fresh so okay now let's run this so to run a specific test you can just pass the file so I'm test unit course yes and we can see you can see that we got a an error here and as I said I'm not editing this screencast I'm only when I'm coughing or something so this is what sometimes happen when I'm writing tests sometimes I forget to add the database migration straight so what's that now let's run it again sir recommend so culture on the final method okay now it's time to write this so there is this way to get this passing match list this step is to return false because that's what we expect now this is what I used to do in the beginning that's what I suggest you guys do in the beginning like the test guide you as you get them an experience you already know what to do so you will skip a few set a few steps but give it time so let's run it again oh sorry it's the wrong method saying okay now it's saying that we don't have the method subscribe to course so let's write it let's just return true for now so third certain the false is true on line 25 which is this one so right now let's actually write some code so first of all let's write to subscribe to our school so let's do something like this courses attach a course this is so many to many relationship let's run it so call two on the final method courses we don't have the relationship obviously let's add it sorry it belongs to me now let's read it so no such table as you guys know mainly so many relationships require a buy a table and the tests are telling us this so let's make it create course user create course user 500 table let's go back to it well I'm not sure why it's not showing up what it's here I don't know what's funny so let's say we want in unsigned integer called course 80 and I use hurry - okay cool let's run it again let me get rid of this site were so favorite starting the false is true so now we actually write some code this is a placeholder we know that this is not the correct code so what I would do is let me think of so I would say this courses where where 80 matches the course eg I would do something like this you could do contains you could do exist but um I'm going to use this one now what let's do a let's make it return a ruling so let's make this let's render I'm cool it's fasting so we are actually testing two features here we are testing that a knows when you are subscribed to a course and he knows and he also subscribes a user so we're actually just capsulated some functionality here I really like to do this I don't like calling this every time prefer to have something more readable such subscribes course it's one of the action so let's go back to our users can subscribe to our success so let's run it specifically to that file so future is our tests future users can subscribe to course yes so it's you failing we already have that tacit so we know that it's working and that's because we are not actually doing anything here so my subscribe the user let's say auth user to get the authenticated user subscribe to course first of course so yeah it's working yeah what I forgot to do is check in a notifications there so I'm really sorry it's really hard to do screencasting keep a check and everything so how do we do this it's really simple we can call it notification facade so let's import it and we will call the fake method I'm not going to go in depth of what it says but it basically swaps the instance of the notification class and every time that you send a notification through the app it's not going to actually send it it's going to store it in memory and then you can check if it was sent so after we've done this we can say notification a third worth sensor to the user we want to make sure the subscribe to course notification was sent and then we can pass a callback that gets a notification object and we can say let me just use course and we can say that the course that is on that notification is the course that we have right here and another thing that I would do is the same as we've done on the other test I would just make sure that the user is not subscribed to the course before starting before starting to test even though I know that's true because we are using database migrations and we have the tested on the method that's alright Assessor we don't have to test it again here but anyway redundancy is not bad at all okay so let's run this so failure let's our units risk false 26 oh sorry that's supposed to go here really sorry you guys that's a shame so figure out starting the force is real line 30 um again what I said before whenever we do anything that changes something we have to refresh thank you sir now I could edit this I could make another take and show some perfect code but that's what happens in reality when I'm writing tests when I'm working sometimes that happens it usually does not but it does happen and it's not a big deal you don't have to write perfect tests all the time and make everything pass and and write the correct as the first so we have we are refreshing it let's run it again cool so right now it's saying that the notification what assert oh sorry it's a search sensor again that happens we don't we can remember every method what I usually do is whenever I don't really remember how the method was called is I write something and I use a plug-in called I don't remember the name but it allows me to go through the method so if I press f12 it shows me a file that contains the method now the method didn't exist so I would press f12 and nothing was gonna work so it would say unable to find a service center okay let's run it again so the expected subscribes course notification was not sent you can see that the name space is round the class was not supposed to be here so let's first write the node generator notification so make notification subscribe to course and let's import it okay I reported so it's still not finding it but uh it's around it's to my Geoffrey notification here it has the proper namespace so we are not setting it let's write some code to do this I'm going to show you something so I'm going to write the run code first so I'm going to say user know if I knew subscribe to course now there's a room thing here we're not passing the course object so right here we are making sure that the the course on the notification object is the same one as we have right here so it's going to fail let me show you guys so I'm just finding property we don't have the property so let's at it let's just create it let's not populate it let's just say public of course so it's trying to get property ID of none object so if we just follow whatever we can see that it happens on line 36 and we know that this this object exists so when I'm not sure what object it's talking about I like to jump in that step so I would say jump and I note efficient jump and I course that way I know that the course exists and I know that notification exists but it might be reason to something so I know that the error the issue is with the notification let's get rid of this so you might be hearing some noise of a truck on the street I'm really sorry let's say we expect a course course equals force I hate this okay let's just so that's funny I was actually waiting to get to that point this is not a really helpful error we don't know what it means and that's because of the laravel exception handling the exception handler is responsible for doing a lot of cool stuff like converting a model not fun exception to a 4:04 HTTP response when you run a board it it's it changes it doesn't show an exception it actually returns a for 403 thing it's a default one or fair one I'm not sure but that's what it does it catches exceptions and do some stuff with it if needed now we have the exception handler running here because we're doing it we are making a request and we need it because when we were testing something like validation the validation is actually an exception the validation failure and it it is converted to a response so we need the exception handler to do its job but when we are not testing something that requires exception handler we can call the without exception handler method what it does is it does not handle an exception just frozen so if we run this again it's going to give you the actual error so too few arguments so we are expecting the course argument but we are not passing anything so let's pass it of course okay that's it miss Bessie now we do have another chest right let's copy a lot of this so let's copy it we don't need this right here we actually can just subscribe the user right now so subscribes course we are already starting to sass with the user being subscribed to the course so okay now we are going to use the exception handler take a look let's copy this right here I'm sorry this right here so right now we want to assert that we have a bad response so let's say we want to make sure that the status is something like four to two which is a validation error and we also want to make sure that we do have errors on the session we're not returning Jason if we are returning Jason we have a specific method for that we are going to cover this later well let me show you guys really quick so a situation validation errors so we want to make sure it has the we can either pass just an array with key so we can say you through message surf like that or we can make sure it's the exact error that we are expecting so let's do this what's best in array and let's pass a key value so let's say the user object so something like the user is already subscribed to the course so we also want to make sure that we are refreshing the user right here and actually we're not supposed to get a 42 we are supposed to get a 302 because we are not returning Jason we only get 42 when a returning Jason Jason validation matters if we're not doing this we're getting 302 issues with reaction to your previous page now let's run it and I'm actually running it with a future here so we can use the future flag to only run a single test but let's let's find everything so we can see that everything passes we have a little says done and yeah that's how I read SAS in the real life we sometimes don't don't make it work on the first try and we have to check things it happens so this is it for this lesson we are ready we are already testing a couple of things on the next lesson let's test the notification that we wrote and let's add some features like making sure that the user can only see the course after he subscribed to it and that let's set some expiration date for cars so users cannot subscribe pass a date and we'll see how where it goes so thank you for watching please if you like this video subscribe to the channel leave a like I do have a TDD newsletter and you can subscribe to it on the description I also really is there the course videos earlier for the subscribers so if you like this video it seems to be helpful and of course there's my tweeter I don't post much but sometimes I do so you can check that out thank you and see you later
Info
Channel: Mateus Guimarães
Views: 10,522
Rating: undefined out of 5
Keywords: php, laravel, tdd, test driven development, clean code
Id: 5wSWYOtBgA8
Channel Id: undefined
Length: 36min 17sec (2177 seconds)
Published: Tue Apr 21 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.