Composer, Autoloading, Namespacing, and PHPUnit!

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
lately for the video tutorials on net touch plus I've been focusing a lot on workflow because I think sometimes more than building some excellent application or script or utility many times what we're most interested in learning is just simple workflow how would I go about setting this up so that it works nicely with this and that many times that can be one of the most difficult parts of getting set up with a new application at least at first until you kind of have your head wrapped around the process so in a previous lesson we focused on requirejs and backbone and getting those to play nicely together with a build process in this lesson we're going to switch over to the server side and focus on combining composer with autoloading and PHP unit for testing all right let's get started of course to follow along you need to first install composer we've covered that several times here on net head so you can search for that on the site or it's a very simple process go to getting started scroll down you can either install it locally using this command in the terminal or as I prefer install it globally once you have composer installed you have access to a huge number of packages created by the community including things like PHP unit so if I go to packages org we can search for PHP unit and sure enough that is available now in my case I haven't already have that installed but if you don't you've never used PHP unit before this may not be the lesson for you it's not a crash course in testing but nonetheless you can install it through composer if you wish for this starter application though we don't really need any packages now within my code editor as I always do we're starting with a blank slate so feel free to work along now the first step once you have PHP unit installed is to test it out so let's see what happens if we try to run PHP unit on an empty project Here I am in the terminal and I'll run PHP unit and notice it's going to give me a list of all the various commands that I can use now because we haven't specified a specific file or folder PHP unit doesn't really know what to do I can't find anything so it just spits out the help information let's create a test directory now within here as I noted this really isn't a lesson on EDD it's just workflow to figure out how can we take advantage of Auto loading and composure and class maps and things like that however if you would like a crash course on test-driven development you can check out the test driven PHP session that we have here on methods just click on the sessions tab now to make sure that everything is working as expected let's just use the obligatory calculator class and we're going to call it calculator test dot PHP which is a good practice so let's see how we might do this we'll say class calculator test and it's going to extend PHP unit framework test case so let's begin with a very simple bit of behavior we will say it should add numbers so test add numbers so if we are testing a class we're doing unit testing here I'm going to assume maybe we have some class called calculator we'll save that to a variable called calc and then what we want to do is I want to make sure that when we run calc add two and two what is returned from that method should equal four now this is very basic stuff so we should all be on board here now let's try to do it again I run PHP unit and now it's still spitting up the help well what if we try to do PHP unit on the test folder okay well that's bringing back something I scroll to the top it says class calculator cannot be found and if you think about it of course that's the case we're trying to create a new instance of calculator but we have not created that so let's see how we might go about doing that within the project folder again I will create one for my app and within here maybe I don't know this could be a libraries directory just simple library classes and within here will create calculator dot PHP class calculator of course if I run that again you're going to get the exact same thing because we have created this calculator class but we haven't referenced it there's nothing signalling that we need to autoload the class so still it can't find it so your first thought might be well let's just require it okay well let's try that as a first step we're going to be using this from the root of our project so we can require our app library's calculator dot PHP that will work if I run it again and I scroll to the top now you can see yes it did find the calculator class but now it's letting you know hey I couldn't find any add method at all that's your next step but this is a bit of a dated practice because if you think about it we would have to pull in all of our classes and dependencies for every single test file so as you can imagine that quickly becomes somewhat cumbersome why don't we instead take advantage of Auto loading using composer so once you have composer installed if I were to run it you'll see yep we get documentation as well but as I noted earlier in our case we're not leveraging any packages however if you're doing some testing you absolutely would I would recommend checking out the mockery package which provides mocks and PHP unit but a much more readable and elegant way than how PHP unit offers mocks out of the box nonetheless we're not going to focus on that we're just going to use composers built-in Auto loading capabilities so let's create a new file called composer Jason and this is where we can specify what to auto load are we doing PS Roo Auto loading are we using just a simple class map what about the packages that we require now we can specify that we want to auto load using this auto load property now within here you have a couple options we can specify we want to follow PS r0 which is a popular convention you can refer to a recent article on net Tut's where we cover all of that it's called PSR huh however I think the easiest introduction at least at first is for us to only specify a class map and then if you want we can take a look at using PSR autoloading in a future lesson so let's change this out and instead as I noted we're going to specify a class map now which directories would we need to auto load well in this case all we are working with is app libraries and that's it so now if I switch back and I run composer install if I switch back notice that we now have this new vendor directory and it contains the auto load PHP and also if I open up the rectory you'll see that it creates a class map so notice that it's simply an array of key values so we have calculator and that point specifically to where that file is stored or if we were using name spacing as we will shortly then that would be updated now one thing I want to show you though before we move ahead what if we had something as well like Apps slash models we would need to run a special command to update this file we need to dump the class map again so we would do composer dump auto load now in this case because we don't have a models directory it can't find anything so let's just do this temporarily because I do think it's important to show you how it would work within models maybe user this will all be deleted by the way all right let's run it one more time but now if I go back to our class map notice that it has updated so keep that in mind anytime you add a new directory to your autoload area then you also need to run composer dump auto load in this case though I can delete all of that go back to composer dot Jason get rid of that dump it one more time so that we get a current version of our class map so if I close these now let's see what has this offered us well if we go back to calculator let's see will this just work out of the box now does autoloading mean that we can just run new calculator and it will immediately know what we're doing well let's try it we get rid of the manual require and now if I run PHP unit test go to the top you'll see now it still can't find that calculator if composer provides this auto loading capability built-in why are we still having to manually include it well that's not actually the case we just need to include the auto load file which you could even do in a bootstrap but for now let's place it within here and then we'll fix that shortly I will require vendor auto load dot PHP and now if I run it again you'll see yes now it is working so you might be thinking to yourself well what did we save before we were requiring the calculator class now you're just requiring the auto load file well we're actually achieving a lot first this required block sidenote it does not need to be placed within the test file you just need to have some kind of bootstrap file where you bring that in and second even if you did keep it in here it would still make for an easier setup so let's get this test to pass I'm going to switch over to our calculator and we'll just create a quick function add you've seen this a thousand times we will return X plus y all right so let's run it and sure enough we are now at green so that's really easy so before we move on the next step is I want to get this autoload require out of this class because for every new class at least at this point I would still have to require vendor slash autoload or I would have to create a custom class that extends PHP unit framework require that and then all of my tests could extend my custom test case but in this case we're going to do something a little different we will instead create a PHP unit that XML file so this is essentially the configuration for running our PHP unit tests and that way when we run PHP unit behind the scenes this file will be read and it will follow all of our settings rather than us having to manually do it each time now I happen to have a short little snippet that I will paste in so notice this is simple XML we are creating PHP unit and we are specifying what the bootstrap should be so that just means before your tests are run do you have some kind of bootstrap file that will do some setup well in this case yes we want to make sure that we load vendor slash auto load next we just have some basic settings you can get rid of a lot of these if you want to keep it simple these are just simple configuration options that I tend to prefer next you can have more than one test suite and that way when you're running all of your tests if you really want to focus on one area of your application you can store that within its own test suite in our case though I just have app tests we're only going to do one and the directory will be tests if I go back to calculator tests I can get rid of this require statement because I know before this test runs we're going to first load the auto load P file now let's try it I will run phpunit alone I don't have to specify test anymore I run that command and we're getting the same thing excellent now the next thing that I want to do I can close this out both of these is I want to implement name spacing if I'm Auto loading these files it's very possible that maybe there will be some other class in my project that I don't even know about that has the same class name and that's why I want to take advantage of name spacing so within my calculator class here we will give it a name space of app libraries notice that we are following the directory structure here app libraries and then the name of the class and that way from outside of it if we want to create a new instance of this class you would do new app libraries calculator so now that we've added our namespace in here something is going to break let's try to run PHP unit again or you could always do something like alias P equals PHP unit or you could take advantage of Auto testing but now notice that we run it and we're back to that same error the class calculator could not be found and that's because think about it we go back to our class map well this is no longer correct because we've added namespacing so let's revise this composer dump auto load and if I come back notice that it has now updated to reference our namespace but still if I run our tests again we're still going to get that error class calculator not found well think about it if we go to calculator test we're just trying to reference it like it's a global class but now we know that we've namespaced it and if you're confused with namespacing atleast an easy way to get started is just think about the way that you would organize files in finder in your folder structure if you have two let's say two songs that have the same name well if you stored those in the exact same folder as we all know that would not be allowed you can't have two files or mp3s that have the same name so you would have to use a different name however if you were to move those into their own folder maybe according to the artist or the band then you could have two files that have that same name but then of course if you do want to listen to song number one well now that you've moved it into a new directory you need to reference it accordingly so let's go back to our tests and do that this time we will do app libraries calculator run it again and now we're back to passing however I'm happy to admit that this can be a little cumbersome some may feel that that is not as readable so let's do this at the top then we're going to say I want to use app library's calculator I want to make sure I use that class and now that I specify that at the top I can remove this all together and bring it back to new calculator again if you want to go back to your folder structure thinking just imagine that as you're going to open app library's calculator and then within there you can open up any file or mp3 that you want and the same is true for namespaces let's run it again to make sure that nothing broke great it's still working so already we're taking advantage of a lot we're using PHP unit properly to unit test our classes we're using composer to bring in any additional packages that we might need like mockery we're using composers built-in Auto loading capabilities we're making use of namespaces we're following a lot of tried-and-true best practices to finish up this lesson let's just consider a couple different options when calling an add method and where things might go wrong we know that when we call add two and two that four will be returned but what would happen if we pass for example an array and null well shouldn't that be factored into the equation should an exception be thrown if the arguments that are passed are non numeric probably so so let's write a test to make that happen we'll say test throws exception if non numeric is passed now something to notice here is that when I create my function name if you're thinking wow that's a really long name that's a bad practice actually no it's not when you're writing your tests you want to make them as descriptive as possible and one of the bonuses to that is when others are viewing your tests it's almost like built-in documentation for them they know hey when I'm using my calculator I have the ability to add numbers but it looks like if I pass arguments that are not numbers an exception is going to be thrown it's free documentation for developers which is really nice so let's see how we might do this well once again we're going to create a new instance of calculator looks like we're repeating ourselves a little bit let's keep that in mind when we start refactoring but nonetheless we will call calculator add a and then maybe an array as the second argument we know that that should not work but let's try to run this PHP unit and let's see what we get unsupported operand types so this means we tried to add the arguments together we come back we're trying to add a string and an array and basically PHP is getting pissed off and saying hey stop trying to make me do things that I can't do well so we should check for this we shouldn't blindly assume that x and y will be numeric so let's take a first step now this will not be the correct choice but I'm going to show you both steps of the way so we can see how to refactor and apply additional tests we will start by saying well what about if X or Y are not integers let's say if not isn't X or not isn't Y if that happens to be the case if either one of them is not an integer so we think right now that means that we should throw an exception Pro new invalid argument exception so we think that will work let's see why that won't work though I'm going to run our test again and now we're going to get this issue class at libraries invalid argument exception not found so that means that it thinks that this is our custom class that is stored within the app libraries namespace but how do we just say no we're just talking about a global class that's built into PHP well in those cases make sure you proceeded with a backslash now we run it one more time and we see it tried to run this test but then an invalid argument exception was thrown so we do know that this is happening however we also know that what we're intending here is to ensure that in exception is thrown so we haven't yet written a test to say we expect an exception to be thrown well we can do that in PHP unit actually a bit interestingly by placing it almost like a dog block here I'm going to say at expected exception and what is the name of the exception that I expect to be thrown invalid argument exception now let's run it and sure enough we're getting two tests passed now I want you to be careful it has to follow this syntax so if you happen to be using a simple comment something like that well no that's not going to work you're going to get this weird issue make sure that you are following this pattern right here but essentially this just says when this method is called we're going to expect an exception to be passed and then within here we write the necessary code that we think should trigger that exception now we think this is good but why don't we consider another option so far we've only ensured that when you add two plus two four is returned and when you add non-integer s-- an exception will be thrown let's try one more up here and let's say this time we're going to expect five but this time I'm going to use two point five and two point five so I'm going to expect five to be returned let's see if that works run it again oh now we're getting an invalid argument exception again so what that means is at some point this line of code ran now if you know your math you know that well is integer probably isn't the right choice we want to just make sure that it's numeric so instead we'll use the is numeric function now if I run it one more time yeah now we're back to passing so this shows that sometimes it's beneficial to consider a variety of different things just in case you worry or fear that they may fail so maybe you just want to double-check that when you add maybe negative 3 & 1 well in that case even when we're dealing with negative numbers that should be equal to negative 2 let's run it and good that's still passing but this starts to get a little bit muddy I'll show you two different ways that we could solve this the first choice might be to store a values array so we could do something like create an array and within here we just want to have the X the Y and what we expect the sum to be next one will be two point five two point five and that should be five and then the third one is negative three one and that should be equal to negative two then we could do a for each statement and we could say for each values as and maybe in numbers that's a bad name but that's okay and then we just run our assert equals again so I'm going to assert that the total is that second index here and our test is going to be just as below calc add number is zero and numbers 1 now I can remove all of this so we've dried up our code a bit and if we run the tests again it's still passing great now the advantage to this is anytime you want to try something else out maybe you want to and again this is a very elementary example but you can imagine for more in depth issues maybe negative 9 and negative 9 well that should be equal to negative 18 we run it and now it's running five assertions rather than four so yes this is certainly a way that you could go about it but we can even do a little bit better using PHP unit let's abstract this out and we're going to create a new function and we're going to call this input numbers and paste the values in now in this case rather than storing it in a variable I'm going to return that now when we call tests add numbers I can get rid of this for each because that's going to be done automatically by PHP unit and we can specify as much by using the data provider option and we called it input numbers so now this function is going to be called for each item within this array and it's going to accept X Y and the sum for this one this one and this one respectively if you were to add another one well then a fourth program would be sent through as well now the only thing that I need to change is to update the numbers so that will be X and Y let's try to run it again and good it's still passing so this is a much cleaner way to go about it when you need to run a function through multiple different options this would be the way to go about it the final thing would be we could keep the new instance of the calculator within this function or if it's going to be shared through all the tests why don't we instead add that to the setup and we'll say this calculator equals a new instance of calculator then right here I can remove that entirely and further clean this up like so and the same for the second option so now we've refactored our tests which is good as well you refactor your production but also there are times when you need to refactor your tests but we run it again but now we can see oh there was an error and if we didn't have these tests we may not have even realized that we had done something wrong so already we are realizing the benefit to this and so we see here is called an undefined method assert equals and that's just a mistake on my part this assert equals and we update it here so we fix our error we run it again and now all of the tests are passing and that will do it for this lesson this project is up on github so have a look through it see if you can extend it see if you can try out some different classes maybe you need to test out some kind of geolocation service where you want to test the latitude and longitude and maybe that will be sent to Google Maps there's lots of different options the most important thing though is that you just dig in and you experiment with it and that's the only way you're really going to learn all of this workflow my name is Jeffrey way and we'll see you later
Info
Channel: Tuts+ Code
Views: 124,903
Rating: 4.9119391 out of 5
Keywords: phpunit, nettuts, jeffrey way, composer, php namespacing, composer autoloading, net tuts, nettuts+
Id: 84j61_aI0q8
Channel Id: undefined
Length: 23min 54sec (1434 seconds)
Published: Fri Jan 18 2013
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.