TIP
Sometimes it is necessary to comment out one piece of code to get another piece to work. This might be necessary during the main development cycle when, for example, the underlying code might be dependent on something that has not yet been written or that contains a known bug. If you have to comment out a piece of code, add a Debug.Print statement just before or after it to highlight the fact that you have done so. It's inevitable that you'll forget to remove the leading apostrophe from time to time, and adding a Debug.Print statement should save you from having to find out the hard way.
Component-level testing is the next level up from unit testing. A component can have fairly straightforward functionality, but it is just complex enough to warrant breaking down the actual implementation into several smaller units. For example, a logical process could be specified that calculates the monthly salary for an individual. This process might consist of the following operations:
- Extract from the database the number of hours worked in the month.
- Calculate the amount of gross pay.
- Add a bonus amount (optional).
- Make all standard deductions from this amount.
Each operation will probably have different requirements. For example, the database extraction will need error handling to allow for the usual group of possibilities (user record not found, database service not available, and so on). The calculations will need to prevent numeric type errors (divide by zero, mainly), and if they are remote components, they will have to raise fresh errors. Therefore, the entire component (for example, CalcMonthlySalary) will consist of four smaller units (GetHoursForEmployee, CalcGrossPay, GetBonusAmount, and CalcDeductions), but CalcMonthlySalary will still be small enough to qualify as a unit (for testing purposes).
To test a defined unit, a series of scenarios should be devised that guarantees every line of code will be executed at some time (not necessarily in the same test). For example, if a function includes an If..Then..Else statement, at least two test scenarios should be devised, one to cover each path of execution. If it is a function that is being tested, defining the expected result of the test is generally easier because the return value of the function can be tested for correctness or reasonableness. However, if you are testing a subroutine, you can check only the effect(s) of calling the routine because there is no return value. I generally have a bias toward writing routines as functions where this is reasonable. For some operations, particularly GUI manipulation, it is not so necessary or beneficial because an error should generally be contained within the routine in which it occurred.
In a small system, the developer would likely perform this level of testing. In a larger system, the developer would still perform the initial test, but a separate individual would most likely conduct a more formal version of the test.