Sunday, 27 January 2019

Faking It

Fig 1. A Mockingbird
As well as mentoring and code review one of my main tasks at work is to improve the test suites and improve the testing and development methodologies we use. This is no small task and has resulted in the publication of a few extensions, one of them is uopz.

Before we continue; I work in the real world, where not all code was written yesterday using the best standards and best methods, and it's fine to say "just fix your code", but totally unrealistic, we have to deal with reality.

You may not hear people raving about using uopz, because for most of us, if you are doing the sort of things that uopz makes possible, there is something wrong with the way you are writing code. This is technically true, of course, nevertheless, we have work to do.

When I first started my current job, our test suite was bound tightly to runkit, and failed all the time. When I wrote uopz and we adopted it, it stabilised and developers could once again get on with their work. All the while we would repeat to each other that we would move away from uopz by improving our tests and code. This hasn't really happened, instead, because uopz allows certain crazy things, they are the crazy things that were being done in tests.

It's five years later, and uopz takes up a fair amount of my time with each new PHP version, it's quite a headache, for a temporary solution. Realising that actually this is entirely my fault because I gave them the tools to work like this, I decided we needed new tools.

Some time ago, I wrote an extension called Componere (latin, composer ... I like latin names), the purpose of Componere is to allow the programmer to (re)define complex types at runtime. I showed this to a couple of colleagues, got some "wow, cool", but they never picked it up. I later realised that they didn't pick it up because it relies on the author having at least some knowledge of the way classes are built internally. So even though extremely powerful, it got ignored.

We required a higher level API, and so I've written a mocking framework in PHP, built on top of Componere that is almost without limitation. It's name is "mimus" which is taken from Latin, "mimic" and shared with the first part of the Latin binomial name for the animals everyone knows as Mockingbirds.

I am fully aware that the ecosystem contains within it many mocking frameworks, however they all have the same set of problems, limitations on what methods you can mock or how. This may be good enough for the vast majority of people, you can just write your code so that you can mock the parts you need at test time. However, if you have 3M LOC, it's not so simple; We need to do some of the things that can't be supported properly if you write the whole framework in PHP, such as stubbing privates, statics, finals. We also have 14 tonnes (number pulled from the air) of tests split across many suites and projects, this makes invoking PHP parsing in PHP several tens of thousands of times unrealistic.  Wipe that cringe off your face, real world, remember ...

While you don't hear people raving about uopz, I happen to know it's used in some very large scale deployments of PHP: I know that there's a number of people out there doing exactly the same sort of horrible things in tests that we were doing, and that mimus is freeing us from, slowly.

We're a month into the switch from uopz and hacking the engine apart to a more modern, more sensible world. The developers are really enjoying themselves using mimus too, which is a bonus, and probably born of the fact that they don't have to feel quite so "dirty" when writing tests.

I'm not going to repeat the readme for mimus here, or show any code, because it's Sunday and you probably don't want that. Tomorrow morning, before you write another test that uses uopz, check out mimus ...

Enjoy the rest of your Sunday ...

1 comment: