In this new series of articles, more focused on the technical side of the development process, François shares with us his encounter with and thoughts on testing.
This reflection is divided into two parts: the discovery of testing issues, which is the subject of this article, and the methodical approach to implementation, which you’ll find in the second article.
Introduction to code testing
I remember the day I discovered the tests.
The concept seemed strange at first.
Writing code that tests code?
A stupid question crossed my mind.
Yes, but how do you test the code that tests the code?
Then I was seduced by the idea.
Okay, I understood the broad outlines:
- Ensuring that a code works as expected,
- Check that a code is operating at the system terminals,
- Ensure that a change does not lead to regression,
- Automate a repetitive, boring task,
- Be much calmer during refactoring phases,
- Go home with the satisfaction of a job well done.
All that remained was to put it into practice. So I threw myself into the deep end, with no experience and no real in-depth knowledge of the subject.
A mistake I was soon to pay for.
I was soon confronted with various problems that were considerably slowing down my ability to produce “real” code, so I had to think outside the box.
I don’t have time to do tests, so we should include them in our costings.
Total failure, renunciation, rejection of a concept that seemed promising.
Of course, testing is time-consuming, but properly implemented, it saves a lot more.
My mistakes
At conferences, I met developers who had clearly been won over by the tests. It was obvious that I’d missed something.
It seemed like a good idea.
As I don’t have much time, I’m going to go through the stack from end to end to test it in its entirety.
Hence the creation of tests that would launch http requests and make assertions about the returned content. If the content returned is what was expected, I extrapolate that the intermediate layers have worked correctly. Brilliant! Not so great…
First troublesome points:
- This can only be applied to a web environment,
- If I want to reuse the business layer in another project, I no longer have any tests,
- Input data can only be sent via http,
- Assertions are complex to create because I have to parse the html return first.
Furthermore, as the entire stack is traversed, it is essential that all layers are present. As the test environment is not a “normal” execution environment (like dev or prod), I need to simulate certain layers (cf. mock). In my case, for example, the user session.
Finally, to be able to make correct assertions, you also need to master the initial dataset. However, I have no direct access to the business layer. I therefore have to create a database specific to the test environment.
Before you’ve even started, you’re already seeing a lot of complications.
Once the environment was in place, another problem quickly became apparent. As test data was centralized in a database, it became common to all tests.
A test that modified the state of this base had a direct impact on subsequent tests!
New course: reset database
As a result, I had to reset the database before each test. It’s a pain and very inefficient! Despite this systematic reset, my tests were still highly dependent on each other. Inserting initial data into the database also had an impact on all the tests.
It became very complicated to modify or add a test.
The test environment must be simple to implement, and adding a test must be a quick and trivial operation. If this isn’t the case, you’ll find that developers are disengaged from maintaining and upgrading them.
The “tests” package gradually became a ghost town where only a few lost souls wandered.
This type of test is known as functional testing, because it aims to verify that an application works in the same way as a human would.
These are what we might call high-level tests.
Other tests of this kind go so far as to automatically reproduce a user’s behavior directly from a browser (cf. Selenium).
Is functional testing inherently bad?
I don’t think so.
They can be very useful for testing the feedback from an api rest, or for testing interfaces. But not for a business layer.
Back to square one, I had to find a test base better suited to my needs. I had to think smaller.