Object-Oriented Programming/Unit Testing

From Wikiversity
Jump to navigation Jump to search

This lesson introduces unit testing and test-driven development.

Objectives and Skills[edit]

Objectives and skills for this lesson include:

Readings[edit]

  1. Wikipedia: Software testing
  2. Wikipedia: Unit testing
  3. Wikipedia: Test-driven development

Multimedia[edit]

  1. YouTube: Unit Testing
  2. YouTube: Writing Unit Tests in Python

Examples[edit]

Temperature
+ absolute_zero_celsius: float {read only}
+ absolute_zero_fahrenheit: float {read only}
+ celsius: float
+ fahrenheit: float
+ Temperature(celsius: float = None,
    fahrenheit: float = None)
+ to_celsius(fahrenheit: float)
+ to_celsius(fahrenheit: float)
+ to_fahrenheit(celsius: float)
- validate_celsius(celsius: float)
- validate_fahrenheit(fahrenheit: float)

Activities[edit]

BMI_Calculator
+ bmi: float {read only}
+ feet: float
+ inches: float
+ kilograms: float
+ meters: float
+ pounds: float
+ BMI(feet: float = 0, inches: float = 0,
    kilograms: float = 0, meters: float = 0,
    pounds: float = 0)
+ calculate_metric(kilograms: float, meters: float)
+ calculate_us(pounds: float, feet: float, inches: float)
- feet_to_inches(feet: float)
- inches_to_meters(inches: float)
- pounds_to_kilograms(pounds: float)
- validate_float(value: float, minimum: float, maximum: float)
  1. Review Wikipedia: Unit testing. Extend the BMI class from the previous lesson. Add unit testing to test all aspects of the class. Run tests automatically when the class module itself is run as the main program.
  2. Update program, class, and method documentation, consistent with the documentation standards for your selected programming language.

Lesson Summary[edit]

  • Unit tests are short code fragments created by programmers or occasionally by white box testers during the development process.[1]
  • The unit test usually should not go outside of its own class boundary. It especially should not cross process/network boundaries, because this can introduce unacceptable performance problems to the unit test suite.[2]
  • The goal of unit testing is to isolate each part of the program and show that the individual parts are correct.[3]
  • Test-driven development (TDD) is a programming methodology in which unit tests are created before the code itself is written. When the tests pass, the code is considered complete. It relies on the repetition of a very short development cycle: requirements are turned into very specific test cases, and then the software is improved in order to pass the new tests.[4][5]
  • TDD follows these steps: 1. Write the code, 2. Run tests, 3. Refactor code, 4. Repeat.[6]
  • Unit tests will not catch integration errors or broader system-level errors because they only tests the functionality of the units themselves.[7]
  • Software testing is a combinatorial problem. Every Boolean decision statement requires at least two tests: one with an outcome of "true" and one with an outcome of "false".[8]
  • It is necessary to create relevant initial conditions. Otherwise, the test will not be exercising the code in a realistic context, which diminishes the value and accuracy of unit test results.[9]
  • It is essential to keep careful records of the tests that have been performed and all changes that have been made to the source code of any unit in the software.[10]
  • It is essential to implement a sustainable process for ensuring that test case failures are reviewed regularly and addressed immediately.[11]
  • It is possible to perform unit testing without the support of a specific framework by writing client code that exercises the units under test and uses assertions, exception handling, or other controls flow mechanisms to signal failure.[12]
  • In TDD, by focusing on only writing the code necessary to pass tests, software designs are often more concise than is achieved by other methods.[13]
  • Have an effective layout of a test case to ensure all required actions are completed. This will improve the readability of the test case, and smooths the flow of execution. Consistent structure helps in building a self-documenting test case. A commonly applied structure for test cases has the following: 1. Set up, 2. Execution, 3. Validation, 4. Cleanup.[14]
  • Even though more code is required when programming with TDD than it is without, the total code implementation time could be shorter. Eliminating defects early in the process usually avoids lengthy and tedious debugging later in the project.[15]
  • The limitations of TDD is that it does not perform sufficient testing in situations where full functional tests are required to determine success or failure, due to extensive use of unit tests. Also, unit tests created in a test-driven development environment are typically created by the developer who is writing the code being tested, which could lead to error.
  • Another concern is that a high number of passing unit tests may bring a false sense of security, resulting in fewer additional software testing activities, such as integration testing and compliance testing.[16]
  • For code visibility, code has to be able to clearly access the code it is testing. However, normal design criteria such as information hiding, encapsulation, and the separation of concerns should not be compromised. Therefore, unit test code for TDD is usually written within the same project or module as the code being tested. In object-oriented design, this still does not provide access to private data and methods. Therefore, extra work may be necessary for unit tests.[17]
  • When using TDD for complex systems, challenging systems requires a modular architecture, well-defined components with published interfaces, and disciplined system layering with maximization of platform independence. These proven practices yield increased testability and facilitate the application of build and test automation.[18]

Key Terms[edit]

automation framework
An automated space outside of the calling context for which it was originally created. Testing in such an isolated manner reveals unnecessary dependencies between the code being tested and other units or data spaces in the program.[19]
extreme programming
A software development process that aims to test everything that could possibly break. In extreme programming, the developer writes a unit test that exposes either a software requirement or a defect. This test will then fail because either the requirement isn't implemented yet, or because it intentionally exposes a defect in the existing code. Then, the developer writes the simplest code to make the test, along with other tests, pass.[20]
parameterized unit test (PUT)
Tests that take parameters. Unlike traditional unit tests, which are usually closed methods, PUTs take any set of parameters.[21]
test case
A specification of the inputs, execution conditions, testing procedure, and expected results that define a single test to be executed to achieve a particular software testing objective.[22]
test-driven development
A software development process that relies on the repetition of a very short development cycle. Requirements are turned into very specific test cases. Then the software is improved to pass the new tests.[23]
test oracle
In computing, software engineering, and software testing, a test oracle, or just oracle, is a mechanism for determining whether a test has passed or failed.[24]
unit
In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method.[25]
unit testing
Unit tests are typically written and run by software developers to ensure that code meets its design and behaves as intended.[26]

See Also[edit]

References[edit]