Читать книгу Beginning Software Engineering - Stephens Rod - Страница 19

PART I
Software Engineering Step-by-Step
CHAPTER 1
Software Engineering from 20,000 Feet
TESTING

Оглавление

Effectively testing your own code is extremely hard. If you just wrote the code, you obviously didn’t insert bugs intentionally. If you knew there was a bug in the code, you would have fixed it before you wrote it. That idea often leads programmers to assume their code is correct (I guess they’re just naturally optimistic) so they don’t always test it as thoroughly as they should.

Even if a particular piece of code is thoroughly tested and contains no (or few) bugs, there’s no guarantee that it will work properly with the other parts of the system.

One way to address both of these problems (developers don’t test their own code well and the pieces may not work together) is to perform different kinds of tests. First developers test their own code. Then testers who didn’t write the code test it. After a piece of code seems to work properly, it is integrated into the rest of the project, and the whole thing is tested to see if the new code broke anything.

Any time a test fails, the programmers dive back into the code to figure out what’s going wrong and how to fix it. After any repairs, the code goes back into the queue for retesting.

A SWARM OF BUGS

At this point you may wonder why you need to retest the code. After all, you just fixed it, right?

Unfortunately fixing a bug often creates a new bug. Sometimes the bug fix is incorrect. Other times it breaks another piece of code that depended on the original buggy behavior. In the known bug hides an unknown bug.

Still other times the programmer might change some correct behavior to a different correct behavior without realizing that some other code depended on the original correct behavior. (Imagine if someone switched the arrangement of your hot and cold water faucets. Either arrangement would work just fine, but you may get a nasty surprise the next time you take a shower.)

Any time you change the code, whether by adding new code or fixing old code, you need to test it to make sure everything works as it should.

Unfortunately, you can never be certain that you’ve caught every bug. If you run your tests and don’t find anything wrong, that doesn’t mean there are no bugs, just that you haven’t found them. As programming pioneer Edsger W. Dijkstra said, “Testing shows the presence, not the absence of bugs.” (This issue can become philosophical. If a bug is undetected, is it still a bug?)

The best you can do is test and fix bugs until they occur at an acceptably low rate. If bugs don’t bother users too frequently or too severely when they do occur, then you’re ready to move on to deployment.

EXAMPLE Counting Bugs

Suppose requirements gathering, high-level design, low-level design, and development works like this: Every time you make a decision, the next task in the sequence includes two more decisions that depend on the first one. For example, when you make a requirements decision, the high-level design includes two decisions that depend on it. (This isn’t exactly the way it works, but it’s not as ridiculous as you might wish.)

Now suppose you made a mistake during requirements gathering. (The customer said the application had to support 30 users with a 5-second response time, but you heard 5 users with a 30-second response time.)

If you detect the error during the requirements gathering phase, you need to fix only that one error. But how many incorrect decisions could depend on that one mistake if you don’t discover the problem until after development is complete?

The one mistake in requirements gathering leads to two decisions in high-level design that could be incorrect.

Each of the two possible mistakes in high-level design leads to two new decisions in low-level design that could also be wrong, giving a total of 2 × 2 = 4 possible mistakes in low-level design.

Each of the four suspicious low-level design decisions lead to two more decisions during development, giving a total of 4 × 2 = 8 possible mistakes during development.

Adding up all the mistakes in requirements gathering, high-level design, low-level design, and development gives a total of 1 + 2 + 4 + 8 = 15 possible mistakes. Figure 1.1 shows how the potential mistakes propagate.

Figure 1.1 The circles represent possible mistakes at different stages of development. One early mistake can lead to lots of later mistakes.


In this example, you have 15 times as many decisions to track down, examine, and possibly fix than you would have if you had discovered the mistake right away during requirements gathering. That leads to one of the most important rules of software engineering. A rule that is so important, I’ll repeat it later in the book:

The longer a bug remains undetected, the harder it is to fi x.

Some people think of testing as something you do after the fact to verify that the code you wrote is correct. Actually, testing is critical at every stage of development to ensure the resulting application is usable.

Beginning Software Engineering

Подняться наверх