Create your own Test::Mojo method

Update:

Part of the broader problem of adding test methods in a composable way has been addressed now in the Test::Mojo::WithRoles system. That said, the original post still contains a solution that is easier in one-off scenarios. Keep reading :-)

Original Post:

Perhaps by now you are aware that Mojolicious has a very powerful test framework called Test::Mojo. It wraps most of the Test::More in with Mojo::UserAgent, Mojo::DOM and Mojo::JSON (and probably some things I have forgotten) to let you really test your app in a deep but pleasant way. That said, what if there is some method you wish it had? Should you monkey patch it into Test::Mojo?

No! There’s a better way! The next version of Mojolicious includes one tiny improvement that opens the world of testing as far as your imagination can take you. It just requires a little cleverness.

For example, let’s say I have some route that will return some JSON response and I would like to see if a certain value inside that data structure matches some regex. Test::Mojo and Mojo::JSON have JSON pointers make the dive-in easy, see for example json_is. Then there are test methods such as text_like, but there is no such json_like. There can never be every combination I suppose. So lets make our own!

Our first thought might be to monkey patch a json_like into the Test::Mojo namespace, but that is fragile! What if json_like is added, perhaps with different semantics? Anyway another module’s namespace is sacred, let’s not touch it. For now let’s use a clever dispatch hack, the same one used by Safe::Isa, that is to store a “method” in a scalar. In the following example (or linked) I do just that:

The method accepts the invocant as usual, then a JSON pointer, a regex and an optional description. The pointer is used to get the JSON data at that particular location from the response. Notice that I increase the $Test::Builder::Level so that if the test fails, it reports the correct line number etc.

Finally the test is run and the response is stored in the new success attribute. All Mojolicious setters return the invocant so the return value from $json_like is the test object, which is how the chaining pattern works. The fact that the result is stored in the success attribute allows the or method to work correctly (which allows additional processing after a test fails in the way that or diag(...) is commonly used for Test::More).

You can see that the $json_like variable is used in place of a bareword method name, the dispatch works as it should, and in this case the test passes. Now that “method” can be used throughout the test script. And no monkey patching was needed.

Another candidate for a fun hack (left as an exercise to the reader) is wrapping the functionality of Test::Deep to do even more in-depth data comparison.

A word of caution however: the success attribute has not been released yet! It is expected in the next release if all goes well. Previously the same task was accomplished via private data. This change is being made to facilitate just this kind of hack! I’ll try to remember to come back and remove these warnings when the change is released.

Enjoy!

(P.S. this was my 100th blogs.perl.org post! Yipee!)

1 Comment

Leave a comment

About Joel Berger

user-pic As I delve into the deeper Perl magic I like to share what I can.