Interfaces galore
or why I create an Interface for everything
TLDR; The answer is tests.
Being able to mock every part of your application individually is a huge benefit when it comes to testing Edge Cases.
Say somewhere in your application there is a call to Str::random(64); which ends up in an HTTP-Header or as a nonce in a JWT.
In your unit test you assert that the Request gets sent and the Header is present, maybe event twice to compare the values of said Header to assert that they are not equal.
If someone were to (for whatever reason) remove the call to Str::random(64); and replaces it with a static but incrementing variable,
your test would still pass. In a huge pull request (which happen, don't lie to yourself) this might just fly under the radar.
Maybe the api changed?
The Tests are passing, no one touched them so It must be fine.
This is of course a far-fetched example,
maybe you are switching away from Laravel and the person just forgot to put a //TODO implement new random string helper here next to the change.
Removing the direct call to Str::random(64); and instead moving that call to a separate class:
class Randomness {
public function string(int $length): string {
return Str::random($length);
}
}
Has several Benefits:
You can easily mock the class by replacing the binding with a Mocked Version. Now your test can assert that the value of the nonce equals the fixed value your mocked
Randomnessclass returns. At the same time it asserts that a call to theRandomnessclass is made. (Of course a second Test for the new class is needed)If someone were to replace that call to
Str::random($length);with something not so random, it would (should) immediately raise eyebrows. Why is the Randomness not random anymore, this is used in many places, this cannot be correct!Leaving the Laravel Ecosystem just got a bunch of method calls easier.
In my case, I had to parse a nested XML structure into a flat JSON structure which then got edited and had to be encoded back into the XML again. Since the XML nodes had no identifying attribute or child node, I generated random identifiers for each one.
I wrote multiple Test cases, XML -> JSON, JSON -> XML, XML -> JSON -> XML, you get it.
The last assertion for each test case was static::assertEquals($expected, $generated); which,
kinda sucks if somewhere in your code, a Str::random(64); appears.
A quick fix would simply be to check for the amount of objects in my JSON,
and to compare all the objects individually except the identifier.
But without checking the identifiers, in case someone breaks something,
the first Test to fail would be the XML -> JSON -> XML one.
The XML generated from the parsed JSON would not match the expected.
But the parsing and generating Tests themselves would pass.
Oh, what a fun scenario… Which I definitely did not run into!