You are currently browsing the Test Me posts tagged: clean code


New Addition to CSRunner: php -l

Speed is addictive.

After speeding up PHP Code Sniffer runs, the slowest job for Etsy was running php -l on all the files.

So, in short, the latest release of CSRunner, version 0.2.1, will execute lint on the recently changed files.

You can also run the lint command separately, but why would you want to do this instead of your precious find piped to a php -l script?

Because this command outputs to checkstyle format!

Which means if you are Jenkins and using the Jenkins Checkstyle Plugin, you can add the resulting checkstyle xml to your list of Checkstyle results. Voila!

Enjoy!

Thoughts on Accessibility with Regards to Testing

In Alternative Thoughts on Sniffs for Useless Method Overriding I discussed the discovery of a horrible dance that some developers will do just to test private functions:

  1. See a private method you want to test in isolation
  2. Upgrade the private to protected
  3. Create a child class implementation of this class in the TestCase file
  4. Override any protected methods, that were actually intended to be private methods and make them now public
  5. Test the new child class instead of the actual class

This violates the only one class per test file rule, as discussed in PHPUnit Coding Standard: Classes

Many claim that they do this because they do not want the methods to be part of the public API, but need to make it protected so they can do this hack. Yet those who argue for this so called solution have nothing to reconcile the fact that they have removed the ability to distinguish between methods that should be override-able by child implementations and those that should not.

In all honesty, if you have functionality that you would prefer not to be in the public API of one object, but it is sufficiently complex to warrant it’s own battery of tests, you should take that as a suggestion to pull that functionality out into it’s own object.

It is a pity to hide something so complex in a private function, and tempt others into exercising copy/paste coding practices to use it.

If you are using PHP 5.3, then you can do another cheat that will let you avoid the number of class violations, and let you keep using the private keyword. Sebastian Bergmann discusses this in Testing Your Privates.

Don’t jump the gun. This is still not license to blindly make things private. Even Sebastian repeats in the post and in the comments:

Just because the testing of protected and private attributes and methods is possible does not mean that this is a “good thing”.

So why am I even talking about these naughty ways to test private methods?

Because I cannot necessarily stop you!

So let me offer an alternative to all of this that should help communicate intent in your code, let you use all the accessibility levels, and keep you from re-hashing reflection calls in your test methods.

Today I put out a new release of the Etsy PHPUnit Extensions. This new release includes PHPUnit_Extensions_Helper_AccessibleObject.

PHPUnit_Extensions_Helper_AccessibleObject is a wrapper for classes which contain private or protected methods that you would like to test in isolation, for some bizarre reason. But, you may only call private and protected methods of the wrapped object that are annotated with @accessibleForTesting.

Why the special @accessibleForTesting annotation on methods in my production code?

With the @accessibleForTesting you will be able to communicate with other developers that while this code is private or protected you intend to test the logic in it. Also, we can easily comb through the code with a static analyzer to find spots in our code that we might want to consider extracting into more reusable places, like another class. Furthermore, we can also sniff for usages of Reflection.* in our tests and useless method overrides, then double back to ensure we move everything to this AccessibleObject method for testing private and protected methods so that we can go back to the loveliness mentioned in the first half of this paragraph.

If you were making the argument for doing the horrible dance to test private methods mentioned in the beginning of this article, then you can certainly get onboard with being more descriptive about your intent with @accessibleForTesting.

For examples, usage, and code: https://github.com/etsy/phpunit-extensions/wiki/Helpers

P.S. This is still naughty! But it’s a compromise I think I might be able to live with.

PHP CodeSniffer for Recently Changed Files

At Etsy we have been running PHP_CodeSniffer as part of our pre-commit. When we ran on the entire code base it took at least 5 minutes, which is too slow for the Etsy Continuous Deployment pipeline.

Immediately suggestions flew in to only run the sniffs on the changed files, but you can’t just define the set of changed files as files that have changed since the last run.

Why not? Because the set of changed files in the next run will not necessarily contain the files that changed. In fact, the clever programmer will watch the code sniffer find errors in his code and will then push the build button again to watch it turn green on an empty change set.

The elegant solution around this would be to maintain a dictionary of files that have violations in them. The Jenkins (or other CI system) job would run phpcs on changed files and the files that were listed in the dictionary of files that have violations. The job would then alter the dictionary to contain the files that are still failing, but maintaining dictionaries is too tedious to satisfy the minimums that we need.

We minimally need a Jenkins job that takes under 5 minutes to run phpcs on all files that have been recently changed without missing file that has a violation.

The solution, in Git:

  1. Find a SHA that was recent enough to not include too many files, but old enough so that there has definitely been at least one change.

    git log --format='%H' --since='-5 days ago' | tail -n1

  2. Now get the list of the files changed since that SHA

    git diff --name-only {$old_sha}..HEAD | sed '/^$/d' | uniq

  3. Pass that list to phpcs

Five days is long enough to account for very long weekends, but for the most part there is always someone reason to have a deployment per day. With the five day window we see runtimes of maybe a minute now.

This solution is not complete however because if you pass phpcs a list of files to run on, then the ignore patterns are ignored. In other words, you have to do the blacklisting of files, sub-directories, etc. on your own.

Ideally, I should probably look at PHP_CodeSniffer to fix this, but in the interim, I give you CSRunner.

CSRunner simply requires an implementation of the Scm interface, and whatever implementations of the Filter interface you so desire. I started with giving it a Git implementation of the Scm that let’s you pass a remote, branch, and a time window for changes, and a Filter implementation that allows you to list patterns as you would in your ruleset.xml to ignore named Blacklist. Rather then wasting so much effort on config files, formats, and parsers, the README gives you nice example of how to write a little script to utilize this code. Honestly, I feel you all can handle it.

Preview: A Unit Testing Standard

As I mentioned in the last blog post, , I have been playing with PHP_CodeSniffer, and I have devised a standard for assessing the cleanliness and efficiency of the PHPUnit tests that are supposed to be unit tests.

If your unit tests pass this standard, then your tests should have taken less time to write, will take less time to debug, and there will be less time spent maintaining because everything in your tests would be perfectly straight-forward and pretty much prove that your interfaces for the code under test are simple to use as there would be no funny business need to prep those objects in your test code. This standard will be part of the tool set I will be presenting at PHPNW, so I will begin unveiling it.

Currently, there are about a dozen things in the standard to sniff for in your unit test code:

  • Filename Suffix Must Be Test.php
  • File Must Contain Class with Matching Name
  • Test and Provider Functions Must Be Public
  • Unused Data Providers
  • Class Must Extend Trusted Test Case
  • File May Contain Only One Class
  • No Interfaces
  • No Private Methods
  • Only Allowed Function Overrides
  • Public Functions Must Be A Test or Provider
  • Cyclomatic Complexity of 1
  • Nesting Level of 0

Some of these could probably be used on non-unit tests, but since unit testing tends to be the simplest, cheapest, and most scalable with a growing workforce and codebase, let’s stick with talking about unit tests.

PHPNW 2011

If you can make it to Manchester, UK for October 7-9, 2011, then you should consider coming to PHPNW 2011. Buy tickets here.

The schedule looks fantastic. Sebastian Bergmann and thePHP.cc will be there. Also, from my limited experience with this conference so far, Lorna Mitchell and crew run a very tight ship, which has left me even more impressed and excited.

I am very excited to say I will be also be speaking at PHPNW

Are Your Tests Really Helping?

Developer testing can reduce debug time, serve as executable documentation, build confidence, expose questionable patterns running rampant in your code, and in general, increase the speed of development and deployment. Tests can also cost you time, sanity, and agility.

This session will not be the same old re-hash of the Misko Hevry talk on testability. Instead of a talk that is generic, syntactically translated from Java to PHP, and neglectful the major coding patterns prevalent in existing PHP 5 code bases, all of which results in the majority of the audience as un-sold, we will look at coding and testing patterns inspired by a real PHP project. We will also discuss how to identify patterns and make small adjustments where testing is and is not helping. The end result will be a toolbox of habits we can use to improve testability and forward momentum in development.

I do honestly appreciate the gold standard talks on “Clean Code” (“Thank you, sir”), but those talks are nearly four years, if not more, old.

PHP is the driver of websites that touch millions, if not hundreds of millions, of users, and it is about time everyone stops doing the same-old hand-me-down presentations outside of a new hire training or a college classroom, and I’m tired of it.

I will try my best to give a great talk that can leave the crowd excited to go home and re-assess what is and isn’t working in the production of his PHP product and where to go from there.

Now, back to writing a less promotional blog post.


Tags