Hacker News new | ask | show | jobs
by mattsah 4899 days ago
Expectations and responses (provided by give()) are actually held internally. Your syntax is cleaner for very simple responses, however will become increasingly complex, particularly when the response itself is determined by a callback. Adding more params would clutter your example terribly. Also, the mime's are passed to callbacks which provide response so that additional functionality can be added, see this recent use-case:

Parody\Mime::create('App\Text') -> onCall('create') -> expect('WTF' . DS . 'Yo') -> give(function($mime) { return $mime -> onCall('underscorize') -> give('wtf' . DS . 'yo') -> resolve(); });

2 comments

Eww, bad formatting, apologize, as I'm not familiar with hacker news comment system, but you can see the case here:

https://github.com/dotink/inKWellToo/blob/master/external/te...

That seems exceedingly clever -- too clever. I'd make some of that functionality a named function and call it from my callback. It took me way too long to figure out what your code did.
I'm not sure I follow. Could you give a hypothetical example?

It's difficult to tell if you are only referring to the passing of the original Mime as an argument... which if you are, I presume is more a limitation of documentation. While it may be clever, it's a pretty standard use of callbacks to have arguments passed to them that may be useful inside.

Obviously, it would make sense to pass an instance of the object as the first argument to every callback.

A mocked class stands in for the original class. All the methods are stubs. Sometimes you need to provide functionality for the stub methods. Isn't it most logical to use a function to provide a stub method's body?

It's my opinion that all the stuff PHPUnit unit does with mocks (and JUnit as it's based on) is because Java didn't have anonymous functions. So you had to call methods to essentially construct code for the stub method body. But if you can provide actual code than all that API is unnecessary.

In 99% of cases I would wager you don't want your stubs to perform much logic at all. You want their returns to be a static as possible. The more logic your stubs perform the greater chance your test may fail due to an error in your test logic.

This is purposeful. The point of passing the original mime object in two-fold. It is first that it allows you to manipulate the object further when and only when the method is called. This is extremely useful for mocking/stubbing very dynamic objects whose behavior may change based on a method call. Secondly, it allows you to return the mimicked object.

Think of a method, for example that might expect two arguments, set a number of properties, and then return itself. Now imagine it has a second method, which may also alter one of those properties and return something else completely. This is pretty straightforward to do with parody:

    Mime::create('Vendor\Project\Class')
        ->onCall('method1')->expect('arg1', 2)->give(function($mime) {
            $mime->onGet('property1')->give('totally');
            $mime->onGet('property2')->give('possible');

            return $mime;
        })
        ->onCall('method2')->give(function($mime) {
            $mime->onGet('property1')->give('new value');

            return TRUE;
        });
I am not readily familiar with the syntax of other frameworks... but this seems a lot more flexible than passing arguments to the callback and forcing untested logic into the callbacks.

As I mentioned in another comment -- this is designed for very strict and context sensitive test cases. In principle, everything you should ever expect when calling a method is to give something and get something back, and maybe that it modifies a property. All of this is possible here, the logic of how it transforms what you get to what it gives is irrelevant, you should know the answer to both as a developer. And by removing that logic from the code, you "fake" only the very explicit expectations of the code you're pretending to be.

I think I finally see where you're going with this -- that's very interesting and clever (in a good way). I might suggest that you need better documentation/examples -- it took me a while to see what was going on.
I completely agree with this, and the documentation will be forthcoming on the GitHub wiki - so please follow and keep and eye out. There will also be an article at some point soon on Nettuts which will give a pretty complete example of it mimicking a new object instantiation to resolve a static dependency on an example class being tested.