PHPUnit 3.5: Less $this Required

Sebastian Bergmann » 16 August 2010 » in New Features » 35 Comments

The feature discussed below has been removed from PHPUnit due to community feedback.

Over the years, I have gotten quite a few "complaints" from PHPUnit users that they do not like typing $this-> as often as they have to:

<?php
class StackTest extends PHPUnit_Framework_TestCase
{
    public function testPushAndPop()
    {
        $stack = array();
        $this->assertEquals(0, count($stack));
 
        array_push($stack, 'foo');
        $this->assertEquals('foo', $stack[count($stack)-1]);
        $this->assertEquals(1, count($stack));
 
        $this->assertEquals('foo', array_pop($stack));
        $this->assertEquals(0, count($stack));
    }
}
?>

As of PHPUnit 3.5, they can write test code that requires less $this-> statements:

<?php
require_once 'PHPUnit/Framework/Assert/Functions.php';
 
class StackTest extends PHPUnit_Framework_TestCase
{
    public function testPushAndPop()
    {
        $stack = array();
        assertEquals(0, count($stack));
 
        array_push($stack, 'foo');
        assertEquals('foo', $stack[count($stack)-1]);
        assertEquals(1, count($stack));
 
        assertEquals('foo', array_pop($stack));
        assertEquals(0, count($stack));
    }
}
?>

Here's hoping that this makes some people happy :-)

Defined tags for this entry:

Trackback specific URI for this entry

35 Comments to "PHPUnit 3.5: Less $this Required"

Display comments as (Linear | Threaded)
  1. Jean-Marc Fontaine
    16/08/2010 at 16:58 Permalink
    I do not want to be rude but IMHO introducing global functions to replace object methods calls sucks.

    Reply

  2. Sebastian Bergmann
    16/08/2010 at 17:00 Permalink
    Using the global functions is optional and I do not recommend it.

    Reply

  3. Jean-Marc Fontaine
    16/08/2010 at 17:49 Permalink
    I am sure you do not recommend it but then why allowing it?

    I mean PHPUnit is a great quality tool which promotes good practices in the PHP world. In my opinion, these global functions are exactly what you are fighting against.

    Reply

  4. Sebastian Bergmann
    16/08/2010 at 17:57 Permalink
    That actually is a good point. Maybe I should remove the feature again. What do others think?

    Reply

  5. Christof
    16/08/2010 at 18:07 Permalink
    Remove it again please, this is just shows people what not to do.

    Next question will be why they need the method and class wrapping the tests. And they would be right in asking so.

    And if they are that lazy, they are probably not writing tests anyway.

    Reply

  6. Phil
    16/08/2010 at 20:43 Permalink
    I'd go with Jean-Marc. I wouldn't consider this to be good practice. If people are so lazy they could still extend 'PHPUnit_Framework_TestCase' and write shortcuts for the methods (i.e. 'ae()' for 'assertEquals()')...

    Reply

  7. Fabien
    16/08/2010 at 21:37 Permalink
    Please, remove that feature. It feels so wrong, and so magic.

    Reply

  8. Wil Moore III
    17/08/2010 at 08:13 Permalink
    I would actually prefer _not_ having this feature. The explicitness of $this-> is worth the extra few keystrokes. In fact, it would save more keystrokes to simply extend PHPUnit_Framework_TestCase and add a few alias methods such as:

    at => assertTrue
    ae => assertEquals
    ...

    --
    Wil Moore III

    Reply

  9. Sebastian Bergmann
    17/08/2010 at 08:23 Permalink
    The feature has already been removed.

    Reply

  10. James
    16/08/2010 at 17:29 Permalink
    Lazy Sods!

    it's 7 characters and, if you type properly it takes less then half a second $this->... there see....

    Reply

  11. Brendon
    16/08/2010 at 17:43 Permalink
    can't say i ever thought that was an issue, why not just have fluent interfaces?

    Reply

  12. chance garcia
    16/08/2010 at 18:08 Permalink
    The sadness I feel from seeing this is overwhelming. Was there really a significant amount of complaints to warrant implementing this?

    Reply

  13. Evert
    16/08/2010 at 18:51 Permalink
    I think it's a bad idea to pollute the global namespace. It would also increase the risk of making PHPUnit incompatible with code that happen to use any of those functions names.

    This is a perfect example of why namespaces are useful. For instance: place all functions in a 'PHPUnit\functions' namespace. It would become an optional feature just for PHP 5.3+ users.

    Reply

  14. Seva Lapsha
    17/08/2010 at 10:15 Permalink
    I agree with Evert - it could be a good compromise for the upcoming PHPUnit 4.

    Reply

  15. Benjamin
    16/08/2010 at 19:28 Permalink
    I second Jean-Marcs opinion. It just feels wrong to call a function/method without an object.

    Reply

  16. Diogo
    16/08/2010 at 20:11 Permalink
    I'm not sure having global functions is as bad practice as some comments here are suggesting.

    Altought I'm not really familiar with PHPUnit, from what I've seen in Functions.php, no function call was really "oriented" to the testcase itself, so using them on $this fashion was more like a matter of keeping all functions on a single place than applying Object Oriented logic.

    As a matter of fact I don't think it makes much sense that class TestCase should extend Assert - or am I missing something? As a rule of thumb I suppose you'd subclass if TestCase "is a" Assert.

    It seems that at some point at the past (and it's just a fictional guess) the test cases looked like PHPUnit_Framework_Assert::assertEquals(0, count($stack)); but it was too "static" and too long to type. Then at that time it could have made sense to extend Assert so it was simpler to just type $this. But I digress.

    So for me it looks more sane to use the static functions from Assert class than extending it.

    I'm also not really familiar with PHP's namespace functionality, but on some other languages you can have the package functions exported to the current scope. Coming from such background it makes sense if we could "use" Assert which exports all the functions without the need of a script defining global functions as gateways. Assuming PHP can't export from Assert into the current scope, Functions.php is fine.

    Anyway, keep up the great job - whatever way community prefers =)


    Diogo

    Reply

  17. beberlei
    16/08/2010 at 20:32 Permalink
    i like it, how about just putting it into some namespace. Functions by definition are global, so i dont see the problem discussed here.

    Reply

  18. kev
    16/08/2010 at 23:20 Permalink
    i don't know a huge amount about phpunit so pardon any ignorance

    looking at your api most of these methods return void, so perhaps they could return self and then the methods could be chained, this would cut down on some of the $this usage (although i don't see it as a problem myself)

    Reply

  19. Weltraumschaf
    17/08/2010 at 08:54 Permalink
    @Fontaine: ABsolutely FULL ACK.

    This shows me again, that the most PHP-Developers are idiots (unless they wouldnt have complaints)! Now you pollute the globales Namsepsace: Very nice! I bet for an beer that someone out there will have the Problem that he need to integrate PHPUnit with an other Software and both introduces an asert*() function. Welcome in hell.

    And please, do not say Namespaces.

    Reply

  20. ace
    17/08/2010 at 09:07 Permalink
    Chaining?

    $this->assertEquals('foo', $stack[count($stack)-1])
    ->assertEquals(1, count($stack));
    ->assertEquals('foo', array_pop($stack));
    ->assertEquals(0, count($stack));

    Reply

  21. Lambda User
    17/08/2010 at 09:30 Permalink
    Removed, huh? I almost thought I'd finally be able to make assertions inside lambdas... Well, what's so wrong with global functions? If they don't rely on global state, then, at least to me, everything's OK with them. Of course, namespacing them or placing them inside a static class (for pre-5.3 compatibility) would be even nicer, but if the main concern is the number of keystrokes, then, well...

    Reply

  22. Jingcheng Zhang
    17/08/2010 at 10:03 Permalink
    Putting these functions into a namespace makes little sence, as you can't "use" functions, instead you have to "use" namespace and add prefix to functions to call them:



    You can alias the namespace, but IMHO it looks ugly.

    Reply

  23. Ionu&#539; G. Stan
    17/08/2010 at 10:17 Permalink
    I don't understand why people are complaining about them being functions. All the assert methods are actually static methods, and all of us are calling them on $this because Sebastian wrote it that way in the docs, otherwise we would see much more self::assertEquals() calls. Static methods and functions are pretty much the same. There are some differences, depending on the PHP version, but... static methods are bad too, you know. Especially in PHP < 5.3 where there's no late static binding.

    So, I'd vote for having assert* functions, although... there's a little problem. These functions would be defined in the global scope for the moment, but I'm sure Sebastian intends to move them into their own namespace later on. Unfortunately this means that people would need to prefix those functions with the PHPUnit namespace or some alias for that namespace, because PHP cannot import all defined functions inside a namespace.

    So, what I'd do then is to provide an Assert or assert class that would contain static methods like equals, isTrue, isFalse and the like. That would allow people to write:

    assert::equals($expected, $actual);

    One downside, static methods are slower than instance methods or functions, but I'm not sure this is such an important issue in test cases.

    Other option is to let them like there were supposed to be in this 3.5 release, and later on, put them in a PHPUnit namespace that a user can alias to "assert" and remove the assert prefix from the functions:

    use PHPUnit/Assert as assert;

    assert\equals($expected, $actual);

    Unfortunately this looks ugly, at least for me. That's why I still prefer an Assert class with static methods. And this would also allow subclassing, while providing shorter names.

    Reply

  24. Giorgio Sironi
    17/08/2010 at 10:52 Permalink
    The assert methods aren't static methods: they need a reference to $this or to some other kind of test suite object so that assertions can be counted (to present the result to the user).

    A fluent interface would be fine in case we need multiple assertions in the same test, but functions... I'm glad it has been removed.

    Reply

  25. Sebastian Bergmann
    17/08/2010 at 12:04 Permalink
    The assert methods are static.

    Reply

  26. Ionut G. Stan
    17/08/2010 at 13:14 Permalink
    Assertion methods are static, go to PHPUnit_Framework_Assert and take a look. Assertion count is done on a static property.

    Reply

  27. Martin1982
    17/08/2010 at 10:55 Permalink
    This kind of felt like going back a few years even though the functions are probably just wrappers. I think every unit testing PHP developer knows the value of good OO code and won't mind putting a few extra $this variables in their code.

    I do like the idea of fluent interfaces though! I'm already very fond of it when making mock objects.

    Reply

  28. Diogo
    17/08/2010 at 14:54 Permalink
    >> I think every unit testing PHP developer knows the value of good OO code
    >> and won't mind putting a few extra $this variables in their code.

    Except that the assertion methods are not Object Oriented.

    Reply

  29. Koen
    17/08/2010 at 13:37 Permalink
    With a language like PHP we'll have to deal with typing $this often. I don't think there's a good way around it.

    Reply

  30. Pete Shaw
    17/08/2010 at 15:03 Permalink
    I've setup a keyboard shortcut so I can just headbutt my keyboard and it types $this-> … easy. Two headbutts and I get self:: … easy everyone should do it, for Pete's sake.

    -Pete

    Reply

  31. Ryan Kulla
    27/02/2011 at 19:17 Permalink
    Agreed. Finding something tedious to type is more of an editor problem.

    Using vim you could either simply make a map that types "$this->assert" for you. For example: putting "nmap a i$this->assert" in your vimrc file allows you to simply type \a to insert: $this->assert

    Or even better, use the SnipMate plugin and create your own phpunit snippet, so that no only will it auto-complete "$this->assert" but will even give you a dropdown list of all the assert methods there are to choose from, as well as being able to create snippets for mocks and other things so you can Tab to each next insert point.

    I appreciate how well Sebastian listens to all his types of users and in the end went with the smart rather than the lazy and misguided.

    Reply

  32. Tarjei Huse
    18/08/2010 at 14:23 Permalink
    I can see the object oriented gestapo got here before me :).

    Yes, globals are ugly in most cases, but this is an optional feature that actually makes the code more readable.

    I would rather see PHPUnit offer some options to those who like to write less code for the same functionality than forcing a specific style of usage.

    PHPUnit is becoming the tool of choice for all test coding in PHP so being open to different styles of coding should be allowed.

    To give an example, look at PHPUnit's Mock implementation.

    It uses the is that it has an abundance of methods - so it is hard to remember all of them. When using Simpletests mock library I can remember the few methods I need. With PHPUnit I must look it up again and again. I often have to think more when reading code written with the fluent interface than the simple calls that Simpletest uses.

    So +1 for keeping the functions. They make the code a bit more readable - at least for me. And maybe I'll use the clicks to write an extra test.

    Reply

  33. lubosdz
    11/10/2010 at 12:38 Permalink
    If guys find uncomfortable with typing "$this->" in $this->assertEqual(...), then what about wrapping calls into static class with intuitive name, e.g assert::equal(..) ?
    lubosdz

    Reply

  34. Tobias Hoffmann
    25/11/2010 at 15:04 Permalink
    I wonder what all the fuzz about global functions is about. If the global functions can be optionally enabled, it would be just perfect for me. Keep it pragmatic, people.

    Reply

  35. Anonymous
    10/03/2011 at 16:34 Permalink
    Currently the feature is broken, I cut&pasted the above example and using PHP-5.3.2 I just got:

    $ phpunit --verbose --debug t.php
    PHPUnit 3.5.13 by Sebastian Bergmann.

    Class PHPUnit_Framework_Assert could not be found in /home/chammers/t.php.

    Maybe you should remove the file if it is no longer supported.

    Reply

3 Trackbacks to "PHPUnit 3.5: Less $this Required"

  1. www.ze-technology.com 18/08/2010 at 15:20
  2. toptutoriais.com.br 21/10/2010 at 16:30
  3. lobach.info 14/03/2011 at 08:26

Add Comment


To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Submitted comments will be subject to moderation before being displayed.