Skip to main content
Engineering LibreTexts

6.1: Tests — Your Life Insurance!

  • Page ID
    32393
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    You are at the beginning of a reengineering project. You know that you will have to perform radical surgery on many parts of a valuable legacy system. You are wondering how you will be able to minimize the risks of changing a system on which your business depends: the risk of breaking features that used to work, the risk of spending too much effort on the wrong tasks, the risk of failing to integrate needed new functionality into the system, and the risk of further increasing maintenance costs.

    The patterns presented in this cluster present effective ways of using tests in a reengineering context to reduce the risks posed by reengineering changes.

    Caveat. Testing is a rich and important subject that can scarcely be covered in any depth in the few pages we devote to it in this chapter. We have done no more than identify a few of the more significant testing patterns that are especially relevant to reengineering projects, and briefly sketch out some of the key issues. Binder, for example, devotes an entire book to testing object-oriented systems [Bin99].

     

    Forces

    These patterns share common forces that concern various elements of risk for the evolution of the legacy system. Each pattern addresses some of these forces in order to achieve a certain balance between effort and risk.

    Reengineering Forces
    • Legacy systems often do not have test procedures defined.
    • Changing parts of a system without introducing new bugs is a challenging task.
    System Development Forces
    • Not every aspect of a system can be tested.

    • Certain aspects are like concurrency and user interfaces are difficult to test.

    • Under time pressure, writing tests is always the task that is eliminated first.

    • Having all the knowledge of a system concentrated in only a few people poses a high risk for the future of the project.

    Human Forces (customers)
    • Customers ultimately do not pay for tests but for new features in the system.

    • An unstable or buggy system is not acceptable for customers.

    Human Forces (developers)
    • Programmers believe they do not need tests, since they write good code.

    • Programmers are not motivated by long term goals since they may leave the project in a month from now.

    • Programmers are more interested in tools and processes that can reduce the time they are losing in identifying problems.

    • Fixing bugs is not fun.

    • Writing tests is not considered to be a noble task.

     

    Overview

    As shown in Figure \(\PageIndex{1}\), Write Tests to Enable Evolution is the root of this cluster. It explains why systematic tests are critical to reengineering projects and what kinds of tests are necessary. It is based on Grow Your Test Base Incrementally which advocates strategies for introducing new tests as you need them.

    When, why, how and what to test.
    Figure \(\PageIndex{1}\): When, why, how and what to test.

    In order to effectively manage incremental introduction of tests, it is important to Use a Testing Framework to structure and organize suites of tests. The testing framework should support you in designing certain styles of tests. In particular, if you Test the Interface, Not the Implementation of components, by using black-box testing strategies, then your tests will tend to be more useful in the face of system changes. Furthermore, if you can Record Business Rules as Tests, then you will have an effective way to keep the business rules explicitly represented and continuously synchronized with the running system even in the presence of radical changes.

    Tests may be introduced at various times for various reasons. Write Tests to Understand advocates investing testing effort in those parts of the system that you need to understand in order to implement changes. More specifically, it is a good idea to Test Fuzzy Features, to Test Old Bugs, and especially to Retest Persistent Problems.

    The patterns in this cluster directly support Migration Strategies for reengineering: Regression Test After Every Change helps you build confidence by ensuring that everything still runs after every incremental change to the system. In effect, tests are a necessary pre-condition to Always Have a Running Version, and they enable you to Migrate Systems Incrementally.


    This page titled 6.1: Tests — Your Life Insurance! is shared under a CC BY-SA license and was authored, remixed, and/or curated by Serge Demeyer, Stéphane Ducasse, Oscar Nierstrasz.

    • Was this article helpful?