You are currently browsing the Test Me posts tagged: Test Smell


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.

An Example: Avoid Private Functions in Unit Tests

@__edorian writes: @elblinkin I can’t seem to make the BowlingGameTest fit your coding standard: [gist here] How does that work out for you? :)

Here is the code he was talking about:

<?php

class GameTest extends PHPUnit_Framework_TestCase {

    /**
     * @var Game
     */
    private $game;

    protected function setUp() {
        $this->game = new Game();
    }

    public function testGutterGame() {
        $this->rollMany(20, 0);
        $this->assertSame(0, $this->game->score());
    }

    public function testRollAllOnes() {
        $this->rollMany(20, 1);
        $this->assertSame(20, $this->game->score());
    }

    public function testRollSpare() {
        $this->rollSpare();
        $this->game->roll(1);
        $this->rollMany(17, 0);
        $this->assertSame(12, $this->game->score());
    }

    public function testRollStrike() {
        $this->game->roll(10);
        $this->game->roll(1);
        $this->game->roll(3);
        $this->rollMany(16, 0);
        $this->assertSame(18, $this->game->score());
    }

    public function testPerfectGame() {
        $this->rollMany(12, 10);
        $this->assertSame(300, $this->game->score());
    }

    public function testThenStrikesThenTwoFives() {
        $this->rollMany(10, 10);
        $this->rollMany(2, 5);
        $this->assertSame(285, $this->game->score());
    }

    private function rollSpare() {
        $this->game->roll(5);
        $this->game->roll(5);
    }

    private function rollMany($rolls, $pins) {
        for (; $rolls; --$rolls) {
            $this->game->roll($pins);
        }
    }

    /**
     * @expectedException InvalidArgumentException
     */
    public function testRollingNegativeAmountOfPinsFails() {
        $this->game->roll(-1);
    }

    /**
     * @expectedException InvalidArgumentException
     */
    public function testRollingMoreThan10PinsFails() {
        $this->game->roll(11);
    }

}
?>

This is one of many canonical examples used for teaching how to use an xUnit framework. It is not necessarily a comment on how to properly test or how to write testable code. It is an example to show that you can potentially use all normal language constructs in a test.

The failed sniffs were mainly due to the private methods.

phpcs --standard=PHPUnitStandard TestExample.php

 52 | ERROR   | Private methods are prohibited; found rollSpare
 57 | ERROR   | Private methods are prohibited; found rollMany
 57 | ERROR   | Function's cyclomatic complexity (2) exceeds allowed maximum of
    |         | 1
 57 | ERROR   | Function's nesting level (1) exceeds allowed maximum of 0

You can refer back to what I said in a a previous article to guess what my opinion is.

One possible solution is that you could copy and paste the internals of the private functions into the tests that call them. Most times private functions are small and not used in as many places in the test as you think. You may have heard that putting the couple lines into a well named private function increases readability, but it rarely does. It leads to jumping up and down in the code file, and most times it is more readable to see the code in a single block. The test shouldn’t be so long that you cannot see it in a single block.

BTW: A spare isn’t always two 5′s. So the private method doesn’t really describe the whole picture anyways.

This test however is pointing to a couple code smells.

First we will pick on rollSpare(). rollSpare() is likely a function that should exist in Game. It is very likely that you will want to rollSpare() when you really are playing a Game and not just when you are testing a Game. As I said in a previous article: Tests should always be treated like every other consumer of the subject under test.

NOTE: If it seems inappropriate to have the rollSpare() as part of the Game interface, then consider having some other class, maybe a helper, encapsulate this functionality within your production code base.

The second private function to pick on is rollMany(). This function adds logic which violates the cyclomatic complexity and nesting level constraints in addition to the no private methods constraint specified in the PHPUnit Unit Testing Code Standard. rollMany() probably cannot be argued to become part of the Game interface or even a helper in production code. This one could be a comment on your test. As in, you have redundant tests can lead to too many test.

It might sound silly that you could possibly test too much, but you can.

When writing unit tests you should write no more than one test per each equivalence class partition. It may sound harmless to do more than that, but you will be wasting precious time. You will waste time writing the extra tests. Your peers will waste time learning those tests. You and your peers will waste time maintaining those tests. All this waste will be for nothing, as the extra tests will not add extra coverage or safety. They are redundant.

rollMany() is an indicator that you have too many tests. You should only need the following tests to test roll()

  • Single Roll
    • Negative Pins
    • More Than 10 Pins
    • Zero Pins
    • Ten Pins
    • A Number of Pins that is greater than 0 and less than 10
  • Multiple Rolls

Uh oh! We missed a couple tests! How are we going to test that we only bowl the ten frames with the correct number of rolls.

You could copy and paste the roll() call the number of times you need to roll the ball, and the number of time you need to roll the ball plus one. You would have to do this for a game with no spares, a game with all strikes, a game with one spare, a game with two spares, a game with three spares, a game with four spares, etc. and don’t forget that in the tenth frame you might need 3 balls! Oy!

Again, this is pointing to a problem with your production code. The interface for Game is too small, or maybe it is that we are missing an object in our model.

If we introduced a Frame, that had the roll() method, possibly like this

<?php

class Frame {

    private $is_final_frame;
    private $rolls;

    public function __construct(
        $is_final_frame = false
    ) {
        $this->is_final_frame = $is_final_frame;
        $this->rolls = array();
    }

    public function roll($number_of_pins) {
        if (($number_of_pins < 0) || ($number_of_pins > 10)) {
            throw new Exception(
                "Must roll 0-10 pins, you rolled: $number_of_pins");
        }

        if (!$this->isComplete()) {
            throw new Exception("Frame is complete");
        }

        $this->rolls[] = $number_of_pins;
    }

    public function isComplete() {
        switch (count($this->rolls)) {
            case 0:
                return false;
            case 1:
                return $this->isStrike();
            case 2:
                return ($this->isStrike() || $this->isSpare())
                    && !$this->is_final_frame;
            default:
                return true;
        }
    }

    public function isStrike() {
        return $this->rolls[0] === 10;
    }

    public function isSpare() {
        return !$this->isStrike()
            && ($this->rolls[0] + $this->rolls[1]) === 10;
    }

    public function getRoll($roll_number) {
        if ($roll_number >= count($this->rolls)) {
            return 0;
        }
        return $this->rolls[$roll_number];
    }
}
?>

…then we could do all our single roll tests and our frame completion tests in a sane manner with no control structures. Our tests would be

  • Single Roll
    • Negative Pins
    • More Than 10 Pins
    • Zero Pins
    • Ten Pins
    • A Number of Pins that is greater than 0 and less than 10
  • Multiple Rolls – Not Final Frame
    • One strike
    • One strike, fail on second roll
    • Two rolls, sum less than 10
    • A spare
    • Try to roll three balls
  • Multiple Rolls – Final Frame
    • One strike plus two more rolls
    • A spare plus one more roll
    • Fail on a strike or a spare followed by enough rolls to total four
    • Two rolls, sum less than 10
    • Fail on three rolls, when sum of first two rolls is less than 10

Finally, we can then have Game deal with Frames instead of roll()s, and can test that the game never goes beyond ten frames, or the number of frames it is given.

Game could look something like this

<?php

class Game {

    private $frames;
    private $current_frame_index;

    public function __construct($frames) {
        $this->frames = $frames;
        $this->current_frame_index = 0;
    }

    public function roll($number_of_pins) {
        if ($this->isComplete()) {
            throw new Exception("Your game is complete");
        }

        $this->frames[$this->current_frame_index]
            ->roll($number_of_pins);

        if ($this->frames[$this->current_frame_index]->isComplete()) {
            $this->current_frame_index++;
        }
    }

    public function isComplete() {
        $max_frames = count($this->frames);
        return ($this->current_frame_index >= $max_frames)
            && $this->frames[$max_frames - 1]->isComplete();
    }

    public function score() {
        $score = 0;
        $previous_was_strike = false;
        $previous_was_spare = false;
        foreach ($this->frames as $frame) {
            if ($previous_was_strike) {
                $score += 2 * ($frame->getRoll(0) + $frame->getRoll(1));
            } else if ($previous_was_spare) {
                $score += (2 * $frame->getRoll(0)) + $frame->getRoll(1));
            } else {
                $score += $frame->getRoll(0) + $frame->getRoll(1);
            }
        }

        $last_frame = $this->frames[count($this->frames) - 1];
        $score += $last_frame->getRoll(3);
        return $score;
    }
}
?>

I would recommend a Game_Factory for setting you up with the number of frames you want in the Game. Partly because it is bad practice to have logic or function calls in your constructor, but mostly because injecting complex objects or pre-populated arrays allows you to get your subject under test (SUT) to a testable state faster. (Note to self: I should probably write up a full example of that in a later article or workshop.) Not to mention our Game is much easier to vary now as we could swap in a different number of Frames or even a different variety of Framess. We could eventually extract a Scorer to handle scoring different Frame combinations. After all, even though this looks like a bowling game, it wasn’t called BowlingGame.

Anyways, I hope you are not distressed by now and think that this is the only solution. There are many ways to code a solution, but hopefully this will help you think about how to look at your tests as a reflection on your production code.

PHPUnit Coding Standard: Control Structures

Finally, on to Control Structures.

This should be short and simple.

In a unit test there should be absolutely no control structures.

Unit tests are meant to minimize your debug time by being small to the point tests on small specific pieces of code.

Typically there will be one Test_Case class per production class which will contain at least one test function per equivalence class partition of parameters for each function.

That may have been a bit much to parse, please read about equivalence class partitioning. They will help you from writing redundant tests

Since unit tests are intended to reduce the time spent debugging, it should make sense that the unit tests themselves should not be subject to debugging.

All logic should be tested. Adding control structures to tests is logic that should to be tested, and things that should be tested are possibly things that you may end up having to debug.

To warn about control structures, the coding standard checks for cyclomatic complexity of 1 and nesting level of 0. Cyclomatic complexity of 1 implies that there is one path through the test which also implies that the reader of your test can read the test from top to bottom and not have to loop or branch to understand it. Nesting level of 0 is just an extra precaution.

Please read the previous articles for some discussion on how to test without control structures.

Applicable Sniffs

Generic.Metrics.CyclomaticComplexity
Generic.Metrics.NestingLevel

PHPUnit Coding Standard: Functions

Now to talk about Functions. This could arguably be more controversial than the Naming and Classes standards.

There will be times where you raise your hand and cry out, “but that violates DRY principles!” or “the xUnit pattern book says this!” I assure you, I will provide further argument in later articles as none of these ideas exist in a vacuum.

Now let’s get to it!

No private methods in test files

Most of you will find yourself doing private methods to make your tests DRY (Don’t Repeat Yourself), but just remember that when things get too dry, they become brittle and break.

Sometimes it is more prudent to copy/paste that line or two into the test method itself. Honestly, it is a lot simpler to read the test in a single block than it is to jump up and down in the test file to track down what is hiding in a private method.

private methods are also cesspools for growing logic. If you read the previous articles about testing, you should know that tests are no place for logic, and that all logic should be considered part of the test framework or production code so that it is tested before use.

Let’s learn from past uses of private methods in unit test cases. Typically, you are either creating a custom assert, a custom setup, or you are encoding business logic.

In the case of a custom assert, please pull it out into the testing framework, or rather as an extension to the framework. I’ll write more about the best ways to do this later, but for now, just pull the asserts out into a class that lives with code that needs to be tested. You can also look at the Etsy PHPUnit Extensions wiki on Asserts and Constraints. Trust me, you will find that others might later need to use your custom assertions for new tests.

In the case of custom setup, we need to look at the problem a little harder. First, could you have used the inherited setUp() function to implement the set up. If yes, then please use that instead. If the answer is no because you have some instances of the SUT (subject under test) that need to be set up one way and some another, then you need to go back to an earlier consideration: can you just copy/paste. If copy/paste is a no go, and you couldn’t even offload some of the set up cost to setUp, then there is a problem with the construction of your SUT. You need to fix your production code because it is far too complicated to obtain an instance of this object. Maybe you can refactor your constructor into something simpler. You might have primitive envy, and could encapsulate commonly used together variables into objects. Another option is, you just might need a factory. While going through the exercise of creating a factory, you should learn more about the patterns for constructing your object. In your test, you can now use the factory to create your object for you, since it is a nicely tested piece of code. Maybe even some of your tests will be moved over to testing the object creation in the factory instead of cluttering the testing of the behaviors of a created object.

In the case where you are encoding business logic, you should seriously ask yourself why this business logic needs to be reconstructed in a test. There should be something in your production code that encapsulates the business logic.

Really, you are trying to test business logic. You don’t want to copy paste it in your test so you put that business logic in a private method, in your test code.

Ok, Mr. Fancy Pants, how is that business logic going to be implemented in production? If you have a method somewhere in your production code that does that business logic, then call that in the test and not the private method that copy/paste-d into the test code. If that business logic is hiding in a private method in your production, maybe you are being overzealous with protection levels. If that business logic is no where to be found in your production code, then why are you testing it. If that business logic is copy/paste-d all around your code base, then why was your test case so much more special than your production code.

It may seem mean taking out the usage of private methods from unit tests, but hopefully you now better understand how the presence of a private method in test code indicates a smell.

Applicable Sniffs

PHPUnitStandard.Testing.NoPrivateMethods

protected methods are reserved for overriding parent methods

If you look though the Test_Case implementations in PHPUnit, you should notice that the methods intended to be overridden for the most part are marked protected. This include setUp and tearDown.

The test case will run just fine if you override it with a public modifier, but it is an indicator to the reader of the test that you are overriding parent behavior. Also, the next criteria that I will present will not allow for methods that are not tests or providers to be marked public.

Just to double-check that you are not lost, these methods cannot be private either because that would definitely not override the function of higher visibility. Also, we do this as a whitelist check so that you do not squeak around the NoPrivateMethods sniff by upgrading to protected.

Applicable Sniffs

PHPUnitStandard.Testing.AllowedFunctionOverride

Only provider and test methods are allowed to be public

By provider, I mean a method you pass to @dataProvider in the phpdoc to provide data to a test method. See: PHPUnit DataProviders

By test, I mean a method that encapsulates a single test in a test case. The methods that begin with test or are annotated in the phpdoc with @test are test methods.

Both of these function types must be public for PHPUnit to see them. When PHPUnit cannot see a provider method, it will error out, but when PHPUnit cannot see a test function, it will silently not execute it.

Tests that are not executed will atrophy and die, but worse, they will confuse those who read the test. Most people will not notice that the modifier on a test function is not public, and they will read the test and assume that it has been executing and is valid. Readers of your test will then try to complete work based on these faulty assumptions and waste their time.

If you intend for you test not to execute then please mark it skipped, incomplete, or delete it.

Never be afraid to delete code when there is version control. It’s one of the many great reasons for version control.

Applicable Sniffs

PHPUnitStandard.Testing.TestOrProviderFunctionsOnly
PHPUnitStandard.Testing.TestOrProviderIsPublic

The final piece of the coding standard, as presented here, is Control Structures. This probably needs no separate article beyond this and the previous two. You should know by now that there should never be logic in you tests.

PHPUnit Coding Standard: Classes

Sorry for the delay, on to Classes

One class per test file

PHP allows for multiple classes per file, but for readability and better integration with your version control system, it’s just generally a good idea to have a single class per file, so why not do the same with your test files as well.

Given that you have one class in your production code file, then you will only need one TestCase class in your test file.

You may be tempted to add a class to your test file because you need a helper, but helpers are usually thought to be necessary because your object is not easy enough to use.

Always stop and look at the code under test before writing a test helper or PHPUnit framework extension. Chances are you are violating some object-oriented programming (OOP) aspect, and you are being unfair to others, who will later touch your code, by adding a test helper as a kludge.

If you have to write a test helper, then you should still resist adding it to the test file. Test helpers, justified or not, usually grow logic, and if it doesn’t have logic yet, it will exist as a bed for growing logic later.

Anything that can grow logic, will grow logic!

All logic should be tested, otherwise it will be just that much more code to debug when something goes wrong. So if you really need a test helper, either add it to another code library or include it with your production code.

Including test helpers with your production code might seem silly at first, but after enough experience you will see just how often that those test helpers will become production helpers.

You may also be tempted to add a class to your test file because you want to manually mock one or more of your objects collaborators or you want to override some functionality from your class under test.

There are plenty of great mocking frameworks. Please use them. Most of the mocking frameworks have great documentation, and if that is not enough to help you learn how to use mocking framework, please reach out to one of the contributors. Open source contributors want you to use their projects, and hearing from those who are lost will only make the projects more intuitive, easier to use, and better documented.

Using mocking frameworks will help with eliminating extra classes in test files that exist because of manually mocking collaborators. So what about overriding some functionality in the class under test? STOP! Listen to yourself! What are you testing if you are overriding part of the object? Do you know what encapsulation means?

Please also see:

Applicable Sniffs

PHPUnitStandard.Testing.ExtraneousClass

Name should match file name (with packaging)

Since we have only one class per test file, why not have the names match?

Aside from keeping things pretty, PHP is typically not happy when more than one class has the same name. Since we have only one class per test file, and you will only be able to save one file with that name in the directory (package) anyway, might as well take advantage of that nomenclature in naming your class as well so you can stop wasting time running most of the PHPUnit test suite before discovering you have a couple classes with the same name.

Applicable Sniffs

PHPUnitStandard.Testing.ClassName

Extend only tested TestCase classes

Please see previous comments about anything that can grow logic will grow logic and having your test helpers in your production code or external library and not in your test code.

Unit tests should help you debug production code, not be included in the code that needs to be debugged.

The TestCase class that your test class extends is part of your test, it is a test helper, and it should be tested. It is possibly even more important to make sure your TestCase base class is tested because you likely have several test classes based on it. If the basis of so many tests in your suite is faulty, what does that say about the relevancy and effectiveness of your test suite.

Applicable Sniffs

PHPUnitStandard.Testing.ProvenTestCase

No interfaces or abstract classes

We have already covered that each test file is going to contain only one class, which is a test class for the class under test with matching name, and that the class will extend a tested TestCase. There will be no test helpers in the test files, so there is absolutely no place in the testing directory for interfaces and abstract classes to live. Simple.

Applicable Sniffs

PHPUnitStandard.Testing.NoInterfaces

Next up, Functions

PHPUnit Coding Standard: Naming

I promised more details about the PHPUnit coding standard, so let’s start with Naming.

Pick a directory just for tests

Having a directory just for tests is a communication point. It communicates that only tests live here. There is no production code here. There is also no reason to ever think that the code in this directory needs to be looked at in addition to production code when debugging an issue, at least, if you follow this PHPUnit Coding Standard.

Applicable Sniffs

PHPUnitStandard.Testing.NoInterfaces
PHPUnitStandard.Testing.ProvenTestCase

Pick a test file name suffix, ie. Test.php

The default test file name suffix in PHPUnit is Test.php.

When you execute

phpunit .

the test runner recursively searches through the current directory for all files ending in Test.php. That means all files without that suffix will be ignored, and you could be inadvertantly skipping a lot of tests.

If for some reason you decide you must have a different suffix, say Tests.php, then you will have specify in a PHPUnit XML config file like so

<testsuites>
  <testsuite name="My Test Suite">
    <directory suffix="Tests.php">.</directory>
  </testsuite>
</testsuite>

Alternatively, you could list each test file, but then you are likely to forget to add new tests to the configuration.

Tests that are not executed regularly are dangerous. Tests that are not executed regularly tend to atrophy. New developers will look at tests has a guideline for how to use production code. If a test is not regularly executed then it is out of date documentation that someone will take as gospel, and essentially, they will be wasting their time.

Applicable Sniffs

PHPUnitStandard.Testing.FileNameSuffix

Match the name of the test file to the name of the file being tested

If all the tests are in a test directory, then we know where to find all the tests.

If all the tests are named in a way that matches the naming of the code under test, then we know where the unit test for a production class file is. We can then quickly answer the questions of

  • Do I have a test for this code?
  • If I do have a test for this code, how can I use this code?

Applicable Sniffs

PHPUnitStandard.Testing.ClassName

Next time we’ll discuss Classes

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.

Alternative Thoughts on Sniffs for Useless Method Overriding

Recently I have been playing with PHP_CodeSniffer.

First I worked on creating a standard for assessing the cleanliness and efficiency of the PHPUnit tests that are supposed to be unit tests. The belief being that 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 the test 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.

Then I moved on to looking at what sniffs could the whole code base could withstand. Mostly, I focused on sniffs that would save us time during deployment. Sniffs that had interpretation and execution impact with a clear resolution on failure, like no duplicate class names, property names, or parameter names, or non-executable code.

Well, while investigating the latter, I found a new sniff to add to the former: Generic_Sniffs_CodeAnalysis_UselessOverridingMethodSniff

I found several violations for this sniff in our tests, and so I went through and deleted them, but before committing I ran the test suite, and let’s just say it did not go so well. But why?

The tests failed because the overriding was intended to make protected functions in the overridden class public so that the functions were accessible in the scope of the test.

One test file had 46 violations. Each violation translates to 4 lines of code, one for the function signature, one for the call to the parent function, one for the function scope closing brace, and a new-line. This gave a grand total of 184 lines that weren’t really helpful. When I told the developer that wrote this test, he begrudgingly admitted that many times he got stuck doing useless maintenance on the test because he added or changed a new protected method. What a time suck?

If you have read enough testing articles about the virtues of using mock libraries, and know not to write your own mocks, then this may cause you to think that you could just sniff for hand written mocks and not bother with this wonderful sniff, but that’s not the same find.

I will probably write a longer rant on why using anything other than public on a function is over-zealous, pedantic, and a waste of your good time to even think about, but for now let’s take this find as a small bit of proof that it might be better to not think of non-public modifiers on functions, methods, and classes.

So what should the developer have done instead? Have 46 more public functions to muddy the interface for his class?

No. That’s being a little too extreme.

One option is to consider if you were being too DRY. It is quite possible that you did extract method too much and now have 46 one line methods, and 46 one line methods that you do not want to have as part of your public interface is messier than 46 more lines in a single method.

Another option is to consider extracting helper objects. Extracting a bundle of methods, or even a single method, into a new class file acknowledges that that these methods do not define this object, they weren’t part of the public interface anyways, and opens up the potential to re-use those little helpers in other places without forcing re-use through an instance of the original class. Then in tests you can use a lovely mock library to mock these new collaborators and not worry about updating the test unless you are actually adding a new interaction between the object under test and the collaborator.

Once you have your class with only public methods you won’t have to waste your time on useless overriding for the sake of upgrading the method protection level.

I love avoiding lots of time sucking maintenance!

Testing Your Mocks

Very few times, is it OK to write your own mock class, by hand, for an existing class.  We’ll save the nitty gritty of that statement for a later rant.  

If you happen across the very rare instance that you need a hand-written mock, then you will definitely want to write a unit test for your mock.  Otherwise, in a unit test, you should never test a mock.

Many times I have seen this awful pattern.  

There is a class like so

<?php

class MyClass {

     public function doAwesome() {

         $param1 = ... // compute this
         $param2 = ... // compute this

         $silly_bar = $this->doSomethingIDontWantToDoWhenITest($param1, $param2);

          return $silly_bar;
    }

    protected function doSomethingIDontWantToDoWhenITest($param1, $param2) {

        // Literally -- Do something that I don't want to do when I test doAwesome

    }
}
?>

with a test like so

<?php

require_once 'AutoLoader.php';

class MyClassTest extends PHPUnit_TestCase_Framework {

    function testDoAweome() {
        $my_obj = new MyClassMock();
        $this->assertEquals("I'm awesome", $my_obj->doAwesome());
    }

}

class MyClassMock extends MyClass {

    /**
      * We'll just return some string to make sure this gets called.
      */
    protected function doSomethingIDontWantToDoWhenITest($param1, $param2) {
          return "I'm awesome";
    }
}
?>

First, if I look at the test, it looks like I am testing a MyClassMock, and not MyClass.

Maybe I should rename this test to MyClassMockTest. WRONG

Why are you testing the mock?
The mock isn’t going to be used anywhere!

Why did the person even write this mock in the first place?
MyClass calls doSomethingIDontWantToDoWhenITest in the doAwesome method that I actually want to test, so if we make the doSomethingIDontWantToDoWhenITest method protected, then I can extend MyClass and override doSomethingIDontWantToDoWhenITest to return something simple without doing any work.

So clever, but SO WRONG!
This is wrong, and this example has put us in an awful trap.
The method doAwesome computes $param1 and $param2 before passing them to doSomethingIDontWantToDoWhenITest and returns the result of that call. Our MyClassMock does not take into account what got computed for $param1 and $param2. Sure, we executed the code to compute $param1 and $param2, but we only verified the results of the mock implementation of doSomethingIDontWantToDoWhenITest. * Slaps Forehead *

How do we fix this?
We have uncovered that doSomethingIDontWantToDoWhenITest is essentially begging for the Strategy Pattern.

Essentially, we need to extract method into a new object, like so

<?php

class MyStrategy {

    public function doSomethingIDontWantToDoWhenITest($param1, $param2) {

        // Literally -- Do something that I don't want to do when I test doAwesome

    }
}
?>

and modify MyClass like so

<?php

class MyClass {

    private $strategy;

    public MyClass($strategy) {
        $this->strategy = $strategy;
    }

    public function doAwesome() {

        $param1 = ... // compute this
        $param2 = ... // compute this

        $silly_bar = $this->strategy->doSomethingIDontWantToDoWhenITest($param1, $param2);

         return $silly_bar;
    }
}
?>

and modify the test, like this

<?php

class MyClassTest extends PHPUnit_Framework_TestCase {

    function testDoAwesome() {
        $param1 = ... // what the value of this should be computed by doAwesome to be
        $param2 = ... // what the value of this should be computed by doAwesome to be
        $strategy = $this->getMock('MyStrategy');
        $strategy
            ->expects($this->once())
            ->method('doSomethingIDontWantToDoWhenITest')
            ->with($param1, $param2)
            ->will($this->returnValue("I'm truly awesome"));

        $my_object = new MyClass($strategy);
        $this->assertEquals("I'm truly awesome", $my_object->doAwesome());
}
?>

The PHPUnit mock object library in this case will verify that the method doSomethingIDontWantToDoWhenITest is called once, with what we expect doAwesome will compute $param1 and $param2 to be, and will then return a value that we can verify gets returned un-altered.

EXTRA BONUS !!!
Besides no longer be confused about what is actually being tested. I improved the re-usability of MyClass. Anyone can now make several MyClass objects that handle $param1 and $param2 differently because anyone can implement whatever strategy he wants by simply composing a new MyClass at construction time with a different strategy.

If you find yourself writing a mock, stop and think. You almost always can re-work your code into something that is more extensible and re-usable with a side benefit of better testability.


Tags