这是用户在 2024-9-23 21:52 为 https://edstem.org/au/courses/17312/lessons/55753/slides/377530 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

7.2.4 Test strategy

In commercial software development the programmer is typically required to ensure their code is as error free as possible before it is handed over to the testing team whose job is to identify errors in the presented program. With large and complex programs, it is vital that all aspects of the code be tested systematically and comprehensively. In order for the testing team to ensure comprehensiveness, they make use of a document called a test strategy. We will be producing a test strategy (in part) for Assignment B.

A test strategy is document that specifies how your class or program will be tested and, after testing, provides documentation of all the tests done, including the results of the tests. This document should be developed before the program code is written as it is important to think about testing before you have an emotional investment in the outcome. Many designers draft up the test strategy based on the class diagram they present to the programmer to implement. The comprehensiveness of the class diagram is therefore important as it provides an overall high-level view of the system.

There are many approaches to developing a test strategy and different organisations will adopt their own specific strategy. In this unit we will learn how to develop a very basic strategy, which typically contains two components:

  1. A test plan. This is a summary of all the tests which will be eventually performed on the program.

  2. The actual tests. These are the specifications/details of all the tests listed in the test plan. Each test will contain the following three components:

    1. Test data

    2. Expected results

    3. Actual results.

When drafting a test strategy before the program has been developed, the only parts of the document that are left incomplete are the actual results. These are added after the program has been implemented and the tests have been run. When this is done, the actual results will be compared to the expected results and if they match then the test was successful. If they don't match then this indicates a problem in the program, or sometimes it indicates there is a problem with the test data.

Testing strategy example

Let's consider the following class shown in the diagram below:

Test Strategy Class

We have been provided with the following specification details:

  • StaffId is a string of three numeric characters.

  • Pay Scale is a single character from the set {A, B, C, X}.

  • Employee Status is either true to indicate currently employed, or false to indicate not currently employed.

Test plan

The following steps outline an approach to a test plan:

  1. Create an Employee object with the default constructor.

  2. Create an Employee object with the non-default constructor:

    • with valid field values

    • with invalid field values

  3. Test all get methods:

    • Test getIsEmployee()

    • Test getPayScale()

    • Test getStaffId()

  4. Test all set methods:

    • Test setIsEmployee()

      • with valid field values

      • with invalid field values

    • Test setPayScale()

      • with valid field values

      • with invalid field values

    • Test setStaffId()

      • with valid field values

      • with invalid field values

It is important to note the following:

  • In the test plan, every method which has a formal parameter must involve both positive and negative testing.

  • If a class has multiple parameterised constructors, then each constructor should be specified as an independent test case.

  • A negative test could involve multiple values. When this happens, each value being tested is shown as an independent subcase under the same test heading.

    The actual tests

    Test 1

    Create an Employee object with the default constructor.

    Test data:

    • staffId: "000"

    • payScale: 'X'

    • isEmployee: false

    Expected results:

    • staffId: "000"

    • payScale: 'X'

    • isEmployee: false

    Actual results:

      <added after the program has been developed>

      Test 2.1

      Create an Employee object with the non-default constructor with valid field values.

      Test data:

      • staffId: "517"

      • payScale: 'X'

      • isEmployee: false

      Expected results:

      • staffId: "517"

      • payScale: 'X'

      • isEmployee: false

      Actual results:

        <added after the program has been developed>

        Test 2.1b.1

        Create an Employee object with the non-default constructor with invalid field values.

        Test data:

        • staffId: "99"

        • payScale: 'a'

        • isEmployee: true

        Expected results:

        • staffId: "517"

        • payScale: 'X'

        • isEmployee: false

        Actual results:

          <added after the program has been developed>

          Test 2.1b.2

          Create an Employee object with the non-default constructor with invalid field values.

          Test data:

          • staffId: "abc"

          • payScale: '6'

          • isEmployee: true

          Expected results:

          • staffId: "000"

          • payScale: 'X'

          • isEmployee: false

          Actual results:

            <added after the program has been developed>

            The rest of the methods can be elaborated similarly to document the rest of the test strategy.

            After the test strategy document has been completed, the implementation of the program can begin (the testing of the implementation would use a Test class—we will not be using that here as our platform doesn't support embedding multiple classes, so we will show a similar output with a test method).

            public class Employee { private String staffId; private char payScale; private boolean isEmployee; public Employee() { staffId = "000"; payScale = 'X'; isEmployee = false; } public Employee(String staffId, char payScale, boolean isEmployee) { this.staffId = staffId; this.payScale = payScale; this.isEmployee = isEmployee; } public void display() { System.out.println("staffId : " + staffId); System.out.println("payScale : " + payScale); System.out.println("isEmployee: " + isEmployee); } public boolean getIsEmployee() { return isEmployee; } public char getPayScale() { return payScale; } public String getStaffId() { return staffId; } public static void main(String[] args) { Employee emp = new Employee(); emp.test(); } public void setIsEmployee(boolean isEmployee) { this.isEmployee = isEmployee; } public void setPayScale(char payScale) { this.payScale = payScale; } public void setStaffId(String staffId) { this.staffId = staffId; } public void test() { //System.out.println("Create an Employee object with the default constructor"); //Employee emp1 = new Employee(); //emp1.display(); //System.out.println("Create an Employee object with the non-default constructor with valid field values"); //Employee emp2 = new Employee("517", 'C', true); //emp2.display(); //System.out.println("Create an Employee object with the non-default constructor with invalid field values"); //Employee emp3 = new Employee("99", 'a', true); //emp3.display(); //System.out.println("Create an Employee object with the non-default constructor with invalid field values"); //Employee emp3 = new Employee("abc", '6', true); //emp3.display(); } }
            Java

            Once the program has been implemented, the last part of the test strategy document is completed by appending the result of the execution for the specific method and affixing any screenshot available of the execution along with any applicable comments as follows:

            Test 1

            Create an Employee object with the default constructor.

            Test data:

            • staffId: "000"

            • payScale: 'X'

            • isEmployee: false

            Expected results:

            • staffId: "000"

            • payScale: 'X'

            • isEmployee: false

            Actual results:

              Test Passed!

              Test 2.1

              Create an Employee object with the non-default constructor with valid field values.

              Test data:

              • staffId: "517"

              • payScale: 'C'

              • isEmployee: false

              Expected results:

              • staffId: "517"

              • payScale: 'C'

              • isEmployee: false

              Actual results:

                Test Passed!

                Test 2.1b.1

                Create an Employee object with the non-default constructor with invalid field values.

                Test data:

                • staffId: "99"

                • payScale: 'a'

                • isEmployee: true

                Expected results:

                • staffId: "517"

                • payScale: 'X'

                • isEmployee: false

                Actual results:

                  Test FAILED!

                  Method not validating length of staffId and value of payScale correctly.

                  Test 2.1b.2

                  Create an Employee object with the non-default constructor with invalid field values.

                  Test data:

                  • staffId: "abc"

                  • payScale: '6'

                  • isEmployee: true

                  Expected results:

                  • staffId: "517"

                  • payScale: 'X'

                  • isEmployee: false

                  Actual results:

                    Test Failed!

                    Method not validating value of staffId and payScale correctly.

                    The remaining methods should be tested along the same lines.

                    As we can see from the above demonstration, the test strategy is a living and typically very long document. While it is relatively simple to perform tests, it is time consuming to invoke each and every method one at a time, capture and then document the final result. While the process is painstaking, it is critical in software development.

                    The code provided above shows the tests commented out because only one test is generally executed at one time so as not to influence the value based on another method. Depending on the object and the test, this can be modified.