Quick Testing Tips: Write Unit Tests Like Scenarios
I’m a big fan of the BDD Books by Gáspár Nagy and Seb Rose, and I’ve read a lot about writing and improving scenarios, like Specification by Example by Gojko Adzic and Writing Great Specifications by Kamil Nicieja. I can recommend reading anything from Liz Keogh as well. Trying to apply their suggestions in my development work, I realized: specifications benefit from good writing. Writing benefits from good thinking. And so does design. Better writing, thinking, designing: this will make us do a better job at programming. Any effort put into these activities has a positive impact on the other areas, even on the code itself.
Where do types come from?
In essence, everything is a string.
Well, you can always go one layer deeper and find out what a string really is, but for web apps I work on, both input data and output data are strings. The input is an HTTP request, which is a plain-text message that gets passed to the web server, the PHP server, the framework, and finally a user-land controller. The output is an HTTP response, which is also a plain-text message that gets passed to the client. If my app needs the database to load or store some data, that data too is in its initial form a string. It needs to be deserialized into objects to do something and later be serialized into strings so we can store the results.
Quick Testing Tips: Testing Anything; Better Than Testing Nothing?
“Yes, I know. Our tests aren’t perfect, but it’s better to test anything than to test nothing at all, right?”
Let’s look into that for a bit. We’ll try the “Fowler Heuristic” first:
One of my favourite (of the many) things I learned from consulting with Martin Fowler is that he would often ask “Compared to what?”
- Agile helps you ship faster!
- Compared to what?
[…]
Often there is no baseline.
Quick Testing Tips: Self-Contained Tests
Whenever I read a test method I want to understand it without having to jump around in the test class (or worse, in dependencies). If I want to know more, I should be able to “click” on one of the method calls and find out more.
I’ll explain later why I want this, but first I’ll show you how to get to this point.
As an example, here is a test I encountered recently:
On using PSR abstractions
Several years ago, when the PHP-FIG (PHP Framework Interop Group) created its first PSRs (PHP Standard Recommendations) they started some big changes in the PHP ecosystem. The standard for class auto-loading was created to go hand-in-hand with the then new package manager Composer. PSRs for coding standards were defined, which I’m sure helped a lot of teams to leave coding standard discussions behind. The old tabs versus spaces debate was forever settled and the jokes about it now feel quite outdated.
Release of the Rector book
TLDR;
Rector - The Power of Automated Refactoring is now 100% completed
Tomas Votruba and I first met a couple of years ago at one of my favorite conferences; the Dutch PHP Conference in Amsterdam (so actually, we’re very close to our anniversary, Tomas!). He presented Rector there and it was really inspiring. A year later I was working on a legacy migration problem: our team wanted to migrate from Doctrine ORM to “ORM-less”, with handwritten mapping code, etc. I first tried Laminas Code, a code generation tool, but it lacked many features, and also the precision that I needed. Suddenly I recalled Rector, and decided to give it a try. After some experimenting, everything worked and I learned that this tool really is amazingly powerful!
Don't test constructors
@ediar asked me on Twitter if I still think a constructor should not be tested. It depends on the type of object you’re working with, so I think it’ll be useful to elaborate here.
Would you test the constructor of a service that just gets some dependencies injected? No. You’ll test the behavior of the service by calling one of its public methods. The injected dependencies are collaborating services and the service as a whole won’t work if anything went wrong in the constructor.
Early release of Rector - The power of automated refactoring
In October 2020 I asked Tomáš Votruba, the mastermind behind Rector, if we could have a little chat about this tool. I wanted to learn more about it and had spent a couple of days experimenting with it. Tomáš answered all my questions, which was tremendously valuable to me personally. When this happens I normally feel the need to share: there should be some kind of artefact that can be published, so others can also learn about Rector and how to extend it based on your own refactoring needs.
Do tests need static analysis level max?
I recently heard this interesting question: if your project uses a static analysis tool like PHPStan or Psalm (as it should), should the tests by analysed too?
The first thing to consider: what are potential reasons for not analysing your test code?
Why not?
1. Tests are messy in terms of types
Tests may use mocks, which can be confusing for the static analyser:
$object = $this->createMock(MockedInterface::class);
The actual type of $object
is an intersection type, i.e. $object
is both a MockObject
and a MockedInterface
, but the analyser only recognizes MockObject
. You may not like all those warnings about “unknown method” calls on MockObject $object
so you exclude test code from the analysis.
Book excerpt - Decoupling from infrastructure, Conclusion
This article is an excerpt from my book Advanced Web Application Architecture. It contains a couple of sections from the conclusion of Part I: Decoupling from infrastructure.
This chapter covers:
- A deeper discussion on the distinction between core and infrastructure code
- A summary of the strategy for pushing infrastructure to the sides
- A recommendation for using a domain- and test-first approach to software development
- A closer look at the concept of “pure” object-oriented programming
Core code and infrastructure code
In Chapter 1 we’ve looked at definitions for the terms core code and infrastructure code. What I personally find useful about these definitions is that you can look at a piece of code and find out if the definitions apply to it. You can then decide if it’s either core or infrastructure code. But there are other ways of applying these terms to software. One way is to consider the bigger picture of the application and its interactions with actors. You’ll find the term actor in books about user stories and use cases by authors like Ivar Jacobson and Alistair Cockburn, who make a distinction between: