Hello, here is Switch. Today, we will introduce program testing.
When we code, we make lots of fonctions witch have different impacts and can be broken for various reason (forgetting an assignment, wrong calcul, messed up pointers, global variables broken and so on). Those function are created to respect known objectives witch should be ensured by the methods. If we want to ensure our code respect the objectives, we need to test it.
Test solutions
At the beginning, you will be tempt to only relies on manual testing. You run your code until it works, adding debug points with logs and so on. The shortcoming of this method is quite obvious. When you code base is very light and you have a small number of features, you can easily cover all required test case by yourself. But it will be a nightmare when you start working on real applications. That leads to the apparition of automated test. Those test can be written on different level and has various usages. Though they run automatically, they have to be written by hand so they come with a time cost. If correctly managed, this cost can be nullify and it can make a team faster.
Testing is generally separated using levels:
- Unit test: low level test witch call a single function and ensure it works as expected.
- Integration test: low level test witch test a function and ensure it behaves as expected with external services. (To abstract Unit vs Integration, we can say a Unit test does not rely on external services while Integration does but they are the same kind of test, isolating a specific feature and ensuring it works).
- Functional/API test: Global test relying on user callable endpoints. They ensure a feature provided to user will behave as it should.
- End to End test: Test using the user interface directly. They ensure the final products correctly mapped function to user interface components.
There are a lot of test solutions build for each of those levels. Unit test are generally integrated directly with the langage (you use C code for C unit test, Go for Go, etc … ). For higher level test, frameworks usually try to abstract the langage behind and allows to express directly features to test (like gherkin witch let you define steps you will map in your own langage).
Test Driven Development
With the popularisation of testing and testing being more and more present and powerful, we have a new way to develop in sight. Instead of coding then write test to ensure code will not broke, we will first write a test then implement required code to make it pass.
When you are used to do testing after writing code, the step is hard to take. If you are in this case, you should try to write only thing you can know without knowing the implementation to create your test and divide test case in 3 steps: Initialize, Do, Ensure. This is a gage that was given to me while looking for solutions to enforce TDD so I also pass it to you.
If you are new to development, I would recommend getting used to it, and that’s what I made this article for.
So, how does TDD works and why should use it ?
There are mostly benefits to use TDD. It will helps you to minimalise the development. As you start by describing what your code must do, you will clarify your idea and fix the behaviour of your code before implementing. So when you implement, you know you can stop when the test pass.
You will write clearer test. As your test does not describe the implementation but the expectation, it will be clear to anyone with a minimal knowledge of code and your product.
Writing good tests
I do not own absolute knowledge on what a good test is. No one does. But some points seems to be proven useful
- Validate border cases, at least one global case, and known errors
- Mocks only relevant thing you own (a mock is a replacement for a part of the code where you enforce result to be return by code). If you use external services, you should use a mock server witch will return a known valid response taken from official server than mocking the client part to return what you would want.
- Clearly separate the initialisation, actions and expectation part.
- Can be used as documentation for developers. If you wrote a clear test correctly commented, any developer should understand how the code works and behave just from the test case.
That’s all for today. From then on, every article I will write including code part will describe test files first and be developed using TDD method. I hope you will adopt the same behaviour though I will never condemn those who do not goes through it.