Making Software Less Fallible
1. Introduction
“If builders built building like programmers wrote programs, the first woodpecker that comes along will destroy civilisation”. - from the Fortune Cookie in Unix
Rather gloomy quote to begin with, but we seized to compare software systems with other mundane things like buildings, cars and aeroplanes mainly because software is more likely to fail than those above. Ironically, for reasons unknown, we developers assume that our programs WILL work. In that context, the bottom line is, to be a good developer, one should not be too confident of the program that one develops. Demoralising and ironical, but true!
Another factor for poor quality is the shorter life cycle of current projects. The fact that System Test is always done before UAT, makes the development team slightly complacent to test all possible scenarios. It is not sure if everyone understands the differences between Unit Test and System Test.
The old adage of Quality to identify ones “internal customers” is paramount in enforcing stricter quality standards to the software we deliver. System Test Team is the internal customer for the development team. Hence it is important that Development Team delivers their program for System Test as if it is delivered to the client.
2. Reducing fallibility
2.1. Why programs are fallible?
Software is not infallible. But fallibility can be reduced by proper testing. Many factors can be identified that attribute to the poor quality of the programs:
- No testing guidelines have been completely laid out in the design document.
- Design documents that are more process oriented. Hence it cannot be used effectively as a basis for testing.
- No test script is followed by developers.
- The test data is not comprehensive enough to cover all scenarios, especially the exception scenarios.
- Developers tend to assume that their programs will work. As a result, scope of the testing gets limited to successful scenarios rather than failure scenarios.
- Unit test is normally carried out with the mindset of a developer rather than the end user. This factor influences more for interactive programs like screens and menus.
- Unit test results cannot be verified completely in situations where verification depends on other modules, which are either being developed or not fully tested.
- Changes made to dependent modules and/or objects are not communicated to the development team, resulting in programs that are already unit tested, failing in subsequent tests. This could be configuration changes affecting interfaces and vice versa.
- Failure to identify all objects for releasing.
- Failure to identify areas requiring Regression test as a result of a fix done.
- Designers fail to keep the design updated.
These are some of the reasons for failures encountered in System Test. Whereas failures encountered in UAT could be due to inadequate System Test and/or the following factors:
- Business Analysts/Architects/Designers did not understand the requirement correctly.
- Business Analyst did not pass on the requirements clearly to the design team.
- Design documents are not clearly stating the requirement and the solution.
- Sometimes, it may not have been possible to simulate the exact test environment for unit test and system test. This is more common in interface modules, where interaction with other external systems is involved.
2.2. What it impacts?
Errors encountered in System Test impacts the project in variety of ways as given below.
- More time and effort required completing the System Test.
- Rework done to fix the bug is often done in haste as the System Test is already behind schedule due to the errors encountered. This affects the quality.
- Retest done by developers after the fix is not comprehensive, as the pressure is upon them to complete the fix. This results in unforeseen side effects in other areas.
- It is possible that some of the developers are no more with the project, when the project moves into System Test. As a result, rework is sometimes done by a different developer. This requires more time to understand the program, than it would have taken to avoid this in the first place. This increases the time to fix the problem.
2.3. How it can be prevented?
Obviously, it is by testing, testing and more testing. We all do testing, but it needs to be that little bit more complete and effective. To make that happen, a good design document and testing guidelines are required.
This section starts by explaining the differences between Unit and System tests. It then goes on to formulate a guideline that can be adopted to ensure that unit test is not something that is “also done” at the end of the development; but it is something that is conceived at the design stage and implemented during development.
2.3.1. System Test Vs Unit Test
For those of you, who are not aware of the subtle differences between the two:
System Test, also known as the Black-box testing, looks at the system as a whole and it is done to ensure the functionality and the boundary conditions of the system meets the customer requirement. It does not test the internal working of the individual module.
Unit Test, also known as the White-box testing is done to ensure that:
- all independent paths within a module have been executed at least once
- all logical decisions are tested on their true and false sides
- all loops at their boundaries and within their operational bounds are executed
- all internal data structures are tested for their validity
- all the user interfaces like screens, messages and other outputs are tested for validity, un-ambiguity and grammatical correctness.
2.4. Where do I begin?
Any attempt at enforcing quality invariably involves an additional effort on documentation. This is a factor that we have to live with.
Testing ideas should be born in design phase. It is painful, but this will only help improve the design that you do as you start thinking in terms of the quality of the program in addition to the client requirements. A simple thing like visualising and listing all possible error messages that will be displayed will help in preparing your test conditions a great deal.
Recommended by LinkedIn
2.4.1. The design document
Following changes should be brought about to the design document:
2.4.2. System testing guideline
The Testing Consideration section of the External Design can provide direction for functionality testing. It should be given as much importance as the solution itself. This section should contain guidelines on what needs to be tested from the functionality point of view. In addition to helping the testing activity, it will help in giving a better impression to the client, as it will be a clear reflection of the depth of testing and quality.
2.4.3. Unit testing guideline
Since Unit Test cases will be too detailed, it cannot be included in the external design. Hence a simple checklist can be prepared separately that will list all Unit Test cases. There will be two components to it.
1. A standard set of test cases that can be used for all interfaces – This will not undergo change. But not all items need to be used every time. The designers can identify what is required from this list, based on the functionality of the program.
2. A second set of test cases that are specific to a particular interface – This should be prepared for each interface afresh during design time. This can be included in the Testing Consideration section of the external design. The standard test cases may be used as the basis to evolve these test cases.
3. Developers have a tendency to write Unit Test Plans after development completes. This is not a good practice. Write down your Unit Test Plans before you start development. This will help you visualise more testing scenarios, without being influenced by the way you coded your program.
3. Conclusion
This article is just a guideline. Neither these guidelines cover all testing scenarios, nor it guarantee that your programs will pass System Test in the first attempt without any tickets being raised. But it should definitely help reduce the occurrences of errors.
Some of the guidelines may look very obvious or trivial to an experienced developer. It is up to the individuals to decide how rigorous the unit testing should be, depending upon on the circumstances like available time, complexity of the programs, etc. A sample unit testing guideline is provided as an appendix. It is not an exhaustive list but something you could develop upon. For most of you to start the testing, these guidelines may not be required at all. But before you release, it may be a good idea to run through such a list to ensure that you did not miss anything.
Finally, my own version of an alternate quote to the one at the beginning:
“Had God designed the Universe the way Architects designed solutions, Big Bang would have failed with a Time Out error!”
Appendix - General Unit Testing Checklist
Parameters and Arguments
Data Elements: Variables and Constants
Nature of Transactions handled
Data manipulation
Exception handling
Database Exceptions:
For external input:
For external output:
Files
Boundary Conditions
GUI
Execution
Post-execution
Code Review
Release
Suresh, I wish you had written this 20 years ago! Nice one :)