Grumpy Testing Sample
Grumpy Testing Sample
Chris Hartjes
This book is for sale at http://leanpub.com/grumpy-testing This version was published on 2013-10-15
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and many iterations to get reader feedback, pivot until you have the right book and build traction once you do. 2012 - 2013 Chris Hartjes
Contents
1 Thanks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Testing Is Good, Testable Applications Are Better . . . . . . . . . . . . . . . . . . . . . 3 Building Testable Applications is Hard . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Environmental Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 3 5 8
1 Thanks
First, Id like to thank my technical reviewers. They caught all the details that I missed and made this guide what it is. So thanks to (in no particular order) Peter Meth, Joel Perras, Matthew Turland, and Remi Woler for their help. Better guides come from the input of others. Second, Id like to thank those in the PHP community who are always pushing the envelope, always speaking loudly and clearly about the importance of best practices while trying to give back to the community at the same time. Those people inspired me to keep writing and speaking about topics that interest me and hopefully interest you. I may feel out of sync at times with the mainstream PHP community but if my online ranting and raving has inspired other programmers to step up their own game, then I am grateful I had an impact. Finally, Id like to thank my wife Claire for sticking with me on my journey from a fresh-out-ofcollege newbie programmer to the well-rounded, well-seasoned, extremely grumpy programmer I am today. Thanks for putting up with the long hours that a programmer spends staring at screens instead of staring into their partners beautiful eyes. My wife is my partner in everything I do. As always, I welcome your comments about anything you see in this guide, any questions you have, or if you just want to get my thoughts on a wide variety of topics related to programming. And baseball too. This guide was built with the help of the awesome folks at Leanpub. My initial decision to do the guide as text with some AsciiDoc markup turned out to make it easier to convert things into Markdown as Leanpub required. I also used Pandoc to tweak some of the content in the three bonus essays I have included in this guide. A big thank you! to Elizabeth Gauthier for the awesome cover. My wife commented on what an incredible likeness it is. Unfortunately, this guide is not aimed at the beginning programmer. Writing testable applications is a hard thing to do and requires that you already have a solid background in programming. This guide is targeted at intermediate-level programmers who have had some exposure to writing tests and want to push their skills to the next level. If you are looking for an introductory guide to writing unit tests I highly recommend the PHPUnit documentation. It will cover all the basics. I can be reached via email at [email protected] and on Twitter at @grmpyprogrammer. I blog on a regular basis at http://www.littlehart.net/atthekeyboard. Thanks for taking the time to check
http://leanpub.com http://www.methods.co.nz/asciidoc/ https://en.wikipedia.org/wiki/Markdown http://johnmacfarlane.net/pandoc/ http://www.phpunit.de/manual/3.6/en/phpunit-book.html
Thanks
out the guide and I hope you find things that help you get a better handle on your ability to test your PHP applications.
Keep your modules, components, libraries, whatever you decide to call them small, readable, and easy to verify that they work as desired in isolation or when integrated together. That way you will have an application that is very easy to write tests for and provide you with some protection against regression errors and other unexpected bumps in the road. The goal is always the same: create a workflow that shortens the time it takes for code to make it from your text editor of choice all the way into production with the fewest bugs possible.
You will have to extract those and put them into a configuration file. The reality is that some applications need refactoring before you can even test them. In this guide Im going to show you how you can build an application that is actually testable. Of course we are starting from scratch so it is easier but I will also show alternatives for refactoring code that might not be so test-friendly. In each chapter we will cover a different topic that will increase your ability to create applications that you can create tests for. Some of the problems you might face are quite easy to solve, while others might require some intrusive changes to make it happen. In order to illustrate a few of what I consider best practices for creating an application that you can easily test, I will be creating a sample application that utilizes many of the things I am suggesting. The code for the application can be found via my Github account Our companion application is based on a website for a simulation baseball league. Ive been in the Internet Baseball League since 1997 and created this version of the site using a now very-outdated version of CakePHP. It certainly gets the job done but Ive been wanting to clean up stuff going on under the hood and take advantage of some of PHP 5.3s features. Rather than duplicate the whole application Ive extracted those parts of it that generate the main page for the site. Its probably the most complicated public-facing part of the site. It incorporates the use of multiple models and fairly complicated use of templates. A great candidate to highlight the value of tests to verify functionality. Even though I have acquired a reputation over the years as being Mister Framework, were not going to use a framework here at all. I thought it was important to show you that although most of the major players in the PHP framework world make it easy to write tests for applications built with them, you can wrap just about any application in tests. Im using a combination of features and design patterns. While Im not addicted to design patterns, Im a believer in the right solution for the right problems Lets take a look at what were using: PHP 5.3.8 installed on OS-X 10.7.2 installed using a modified Homebrew recipe The Xdebug extension for code-coverage reports The APC extension for boosted PHP performance Twig for templating Postgres as the data store
Pimple, a dependency injection container that is used as a registry of objects and values needed by other parts of the application I have also tested this application in an Ubuntu 10.04 (Lucid) virtual machine on my MacBook. More on the role of virtual machines in testing in a later chapter. For the application architecture I decided to go with a Page Controller structure for each section of the application. If youve used a framework youve been using an application with a Front Controller structure. This means that every request goes through a single file and then the framework itself interprets the request and determines what controller and action pair needs to be executed. A Data Mapper pattern as outlined in Jason Sweats awesome book on Design Patterns is used to provide access to the database. If you think you might have to change your data store, whether its moving to a clustered solution or switching to one of the newer NoSQL options out there, a data mapper will help make that change easier. In this guide I have only given you a glimpse at the tests that accompany our companion article. Please grab a copy of the code from Github and play around with the application and tests yourself. The code can be downloaded at https://github.com/chartjes/building-testable-applications and I think having the source code will make a lot of the concepts outlined in this guide easier to understand.
http://pimple.sensiolabs.org http://www.phparch.com/books/phparchitects-guide-to-php-design-patterns/ https://github.com/chartjes/building-testable-applications
4 Environmental Consistency
When it really comes down to it, building your application in a way that it can be easily tested requires discipline and attention to detail. Lots of it. I tell you this because you have to do a lot of work before youve even written a line of code. Undisciplined developers end up experiencing a large number of problems that are really fixable. If youve ever come across the phrase well, it worked for me on my computer / laptop / slice / EC2 instance then you will understand what Im getting at. Ive uttered those words from time to time when 100% convinced that my environment wasnt the problem. What can be done to help out with this problem? If you can do only one thing that is not related to code to help make your applications easier to test (automated or otherwise), make sure that the environment you develop your application in is as similar to the environment where it will be deployed as possible. The only difference between your development environment and your production environment should be the data you are manipulating. It is increasingly rare to come across an application that is more than just one PHP script that does not rely on other tools. Even look at the simplest programming stack available to us: LAMP, or Linux + Apache + MySQL + PHP. A project I am working on also includes MongoDB, Redis, APC, and Memcached. Im probably leaving out a few other minor components, but even that list shows how complex a relatively simple application can get. Whatever components you choose to use, it is vitally important you make sure that every environment is using the same one. The easiest way to accomplish this is to actually separate your development environment from whatever you are doing your development work on. This usually means you have two choices: use virtual machines locally or virtual machines remotely. My personal preference is to use virtual machines locally. Most modern computers can run a 512MB to 1GB virtual machine image without trouble. In fact, you would be surprised how responsive a 512MB virtual machine is when doing development work, even when running a few extras like MySQL and even Memcached. To do work on a local virtual machine, I feel like you really have two choices: VMWare or Virtualbox The only real difference between VMWare and Virtualbox is that while VMWare is free, it is not open source like Virtualbox. I prefer to use open source solutions so I go with Virtualbox. Use whatever tool you feel comfortable using, but they both accomplish the same task: letting you run a virtual machine containing the operating system of your choice on your own machine. For both choices
http://mongodb.org http://redis.io http://memcached.org http://www.vmware.com/ https://www.virtualbox.org/
Environmental Consistency
there is an abundance of information on how to set things up so you can even locally edit code that is on the virtual machine. For VMWare folks, the most comprehensive link I could find on setting things up for you to do local development was this blog post about creating a development environment for Drupal using VMWare Fusion and CentOS. If you go the Virtualbox route I recommend the use of Vagrant, a tool that uses Virtualbox to help you build and distribute virtualized environments. Once you have things configured just right (you can use tools like Chef or Puppet) you can create developer and production instances that can be shared between your team in order to develop and test your application. Why is this such a good approach? You can experiment with your application and simply trash it if you do things like accidentally delete the database or screw up a configuration file for one of the associated components your application relies on. You dont have to use Chef and/or Puppet as Vagrant can just use a shell script as part of your provisioning process. Technical reviewer and physicist-turned-machine-language-programmer Joel Perras had this advice to offer me about Vagrant: Use RVM to install the latest Ruby (1.9.3 as of right now), and then install Vagrant in its own gemset. This will save you a lot of trouble down the road. I once had to spend 1.5 days debugging a Vagrant install that would basically crash every time it loaded up, and it turned out to be an issue with the Ruby version that the developer was using which was different than the one that I had been testing it on. The irony of that wasnt lost on us. You dont need to go crazy using Chef/Puppet for provisioning. Vagrant also supports a provisioning method that lets you point it to a shell script that will just be executed, so you can fill that simple text file with a few lines of apt-get foo, and thatll let you get pretty far without needing the brain twist that is Chef/Puppet. Now, if youre not comfortable messing around with virtual machines on your own desktop, a great fall-back option is to do your development work on a remote server. VPS accounts (Virtual Private Server) are great for this, along with using cloud computing services like Rackspace or Amazons AWS to create remote environments that you can do your work in. My current employer has our development servers running on Amazons EC2 service. For those who are comfortable working from a CLI (Command Line Interface) doing your development work is as easy as connecting to the remote development instance using SSH and then
http://janaksingh.com/blog/drupal-development-osx-vmware-fusion-and-centos-53-43 http://vagrantup.com http://www.opscode.com/chef/ http://projects.puppetlabs.com/projects/puppet/ http://www.rackspace.com http://aws.amazon.com/
Environmental Consistency
10
editing code using your choice of editor designed for the CLI (Vim or Emacs, usually). For those not so comfortable working like that, with a little effort you can edit those files remotely if your GUI editor supports connections via SFTP or SSH. I have found that the performance hit from waiting to save those files remotely gets annoying real fast when you have to make all sorts of little changes. I did not find the experience of using TextMate along with ExpanDrive an enjoyable one. My crankiness about network latency and how certain plugins for editors like Vim and Textmate behave over a network connection aside, you should consider the advantages that the use of virtual machines for development work can give you. Distributing virtual machines configured for the needs of your application is the ultimate in consistency. We have also witnessed the rise of services like Orchestra and Zend PHP Cloud for those looking for a managed, pre-configured environment to run their PHP applications in. I like these services because they actually help you in terms of consistency. Part of the reason is because they themselves have standardized what version of PHP they will support, what version of MySQL they will support, and other components they offer. The difference between something like this and services like EC2 or Rackspace is that you cant really run a version of it in your local development environment. While I really like things like Orchestra and PHP Cloud, you have to be careful not to deviate too far from the versions being offered when setting up your development environment. Whatever solution you choose, keep in mind the goal: a consistent environment for all locations that your application will exist in.