This article is not intended to cover the whole testing process due to its vastness. Having a glance at its Wikipedia page could give an idea of it. I am going to cover only the tip of the iceberg, but it is important to remind that bugs cannot be eliminated from the software, but in contrast, they must be discovered as soon as possible.
The higher is the time passed since the bug come into the system, the higher is the cost to fix it.
So any techniques that could be useful to identify a bug should be used, taking into account the resources available and the type of system to be implemented.
I am going to focus to the developer point of view: what a developer can do (related to software testing) to improve the quality of the code? The first word that comes to mind is TDD. Of course, as already said, this isn’t the only way to implement software testing, and it is far from me saying that it is enough, but surely it is a good starting point. I strongly believe that TDD/BDD are very supportive techniques that could help writing more robust and stable software. The problem is mine: I haven’t ever applied it from scratch so far, so I decided to fill this defect from now on.
Although I have been programming since about 5 years, I think to have very few practical experience about software testing. Please, don’t misjudge me about that. In past I wrote some test, but usually working in an already set up environment, by writing small tests regarding the functionality I was adding to the system. Here I am speaking about establishing a test-oriented development process.
I won’t consider any language specific framework, but I am going to define only some of the main keywords.I am going to dive deep in details of some specific framework (hurrah, practice!) in some specific article, but not here.
Unit test refers to a single unit of code. What actually is a unit? According with the paradigm used, a unit code can be a function or a class in case of object-oriented programming. The important thing is that, unit testing should not be performed by considering the success case only; on the contrary the unit test should take into account especially the corner case, in a defensive programming manner. Why? Because as a developer, you will try the normal workflow dozens, hundreds or maybe thousands of times.
On the other hand, integration tests should refer to the interaction of multiple units of code, by trying to locate interface issues. The integration tests can be seen in a hierarchical way: once a group of units are tested, it can be considered at the same time as a unit, a single module, to be integrated with other modules, so an integration test can be performed in an upper layer, and so on. Anyway the importance of the integration test should not be overlooked, since that with unit testing only, it is not possible to identify defects at the interface level.
Mocking during test is fundamental. It is the process of creating an object that can simulate the behavior of a real object. It is necessary to simulate the behavior of a component because in the real world, often a unit is composed or depends on other units. To be sure to isolate the code to be tested, to avoid the side-effects can occur in other units, mock objects should be created, objects that simulate what the real object would do, but without the risk of defects that can occur externally with respect the unit to be tested.
Test-Driven Development is a software development process which involves the creation of the test before actually implementing the functionally. The process involves the following steps:
- Verify if the actually design fits good with the functionality to be added.
- If necessary, refactor the code to adhere to the new feature.
- Repeat the tests, to be sure that after refactoring everything still works properly.
- Write the tests for the new feature (at this point, all the new tests should fail).
- Implement the functionality to adhere to the specification represented by the tests (at the end of this step, all the tests should pass).
- If necessary refactor the code just implemented (cleanup if necessary, remove duplications, etc…).
- Run the tests.
The upside of the process is highlighted by the steps 1. and 4.: the step 1. permits to apply the refactoring of the existing code without being scared of it, and without leveraging the confidence; the step 4. is useful to maintain the code always clean to improve readability and maintainability; it could be useful also in some case, to try to figure out, if there is a solution with improves the performances, and such operation could be performed on step 4.
Behavior-Driven Development can be seen as a specialization of the aforementioned TDD, but it is oriented to the user. It involves the definition of the tests as a description of the desired behavior. It permits a clearer way of communication among different actors, when the process involves not only developers, but also QA Testers, which can define the specification of the tests in a domain-specific language, and then the developers can translate them (by means of automatic tools also), in a specific programming language.
If I am not the only person in the world to have not yet established a real TDD strategy in the daily job, I strongly recommend giving it a try. Keep in mind, a very robust system, should be be tested as much as possible, from every perspective, both functional and not function, by taking into account also features too often overlooked like security and performance; so please consider investigating also on performance test and security test; I will try to describe them in a related post.