tags:

views:

292

answers:

5

At the risk of being flamed... what advantage does enforcing calls to methods rather than functions have in a context where the context is implicit.

Considering that PHP's syntax is so ugly for calling methods why would PHPUnit's creators have enforced its usage?

If the framework had set a global "currentTestCase" object and then transparently associated failed asserts with that object we could be writing:

assertEquals("blah", $text);

as opposed to the equivalent, but verbose:

$this->assertEquals("blah", $text);

What exactly do we get by using OO in this context.

Please enlighten me.

A: 

at the end of the day, this is a design decision made by the authors of PHPUnit ... asking why that decision was made on a third party website (ie. StackOverflow) is about as useful as asking patrons of a North Dakota tavern about the mathematical calculations used by NASA ;-)

Joel Martinez
A third party is often the best person to ask since they don't have a vested interest. And in this case, where the answer is quite subjective, there are hundreds of arguments for and against. Just wanted to know what gut level answers I'd get out of a community of developers that are probably not invested in the project.
Allain Lalonde
+3  A: 

One good reason is that assertXXX as a method name has a high risk for naming clash.

Another one is that it is derived from the xUnit family, which typically deals with object-oriented languages - Smalltalk initially. This makes it easier to related yourself to your "siblings" from e.g. Java and Ruby.

Robert Munteanu
+2  A: 

Because PHPUnit is derived from xUnit and that's how xUnit does it.

Why does xUnit do it that way? I'm glad you asked. The original reason, as Robert points out, is that xUnit comes from Smalltalk and was popularized by JUnit in Java. Both are OO-or-nothing languages so they had no choice.

This is not to say there are not other advantages. OO tests can be inherited. This means if you want to test a subclass you can run all the parent's tests and just override the handful of test methods for the behaviors you've changed. This gives you excellent coverage of subclasses without having to duplicate test code.

Its easy to add and override assert methods in PHPUnit. Just subclass PHPUnit_Framework_TestCase, write your own assert methods and have your test classes inherit from your new subclass. You can also write default setup and teardown methods.

Finally, it guarantees that the test framework's methods aren't going to clash with the thing that they're testing. If the test framework just dumped its functions into the test and you wanted to test something that had a setup method... well you're in trouble.

That said, I hear your pain. A big test framework can be annoying and cumbersome and brittle. Perl doesn't use an xUnit style, it uses a procedural style with short test function names. See Test::More for an example. Behind the scenes it does just what you suggested, there's a singleton test instance object which all the functions use. There's also a hybrid procedural assert functions with OO test methods module called Test::Class which does the best of both worlds.

Considering that PHP's syntax is so ugly for calling methods

I guess you don't like the ->. I suggest you learn to live with it. OO PHP is so much nicer than the alternative.

Schwern
Fair enough, and I agree with the idea of extending your existing TestCases, but overriding the assertion methods seems like bad form. For reference, I'm not anti OO, just when it's unnecessary . Thanks for the Test::More link +1
Allain Lalonde
Not just overriding, but adding your own asserts specific to your needs. Extremely handy. For example, Drupal's SimpleTest fork lacks a way to assert that two arrays are equal, so I've written assertArrayEq(). Its assertEquals() lacks failure diagnostics, it just says they're not equal but I need to know the values for debugging, so I wrote my own assertEq() which does show me the values and speeds debugging.Perl programmers were wary of OO 10 years ago so I figure the PHP community will be coming around soon. :P
Schwern
A: 

Having the test cases in class-methods saves work for PHPUnit. Due to lack of built-in intelligence PHPUnit couldn't find or handle pure test functions. Only having to recognize the ->assert*() messages -in a simple boolean chain- again saves processing logic (for PHPUnit, not the test case author). It's all syntactic salt that saves overhead from the PHPUnit/SimpleTest point of view.

It wouldn't be a technical problem to capture error/warning messages, exceptions or recognize PHPs native assert() statement. It's not done because a difficult API looks more enterprisey.

mario
+1  A: 

Not a direct answer, but as of PHPUnit 3.5, you do not have to write $this-> anymore. PHPUnit 3.5 added a function library for Assertions, which you have to include

require_once 'PHPUnit/Framework/Assert/Functions.php';

Then you can do

assertEquals('foo', $bar);

See Sebastian Bergmann's Blog post about it

Gordon