Fundamentals of Python: From First Programs Through Data Structures Chapter 12 Tools for Design, Documentation, and Testing Objectives After completing this chapter, you will be able to: • Write scenarios and use cases for the analysis phase of a simple software system • Design a simple software system in which the classes have the relationships of aggregation, composition, and inheritance • Use UML diagrams to depict use cases, relationships among classes, and collaborations among objects in a simple software system Fundamentals of Python: From First Programs Through Data Structures 2 Objectives (continued) • Write preconditions and postconditions for methods • Raise exceptions in methods when preconditions are violated • Generate Web-based documentation of classes • Write simple unit tests for classes Fundamentals of Python: From First Programs Through Data Structures 3 Introduction • A program must be well designed, thoroughly documented, and carefully tested – A good design is essential to solving any complex problem – Well-designed and well-written code is, to a certain extent, self-documenting – No matter how carefully you design and document a program, you need to test it with equal care • Computer Assisted Software Engineering (CASE) tools include debuggers, version trackers, profilers, and test beds Fundamentals of Python: From First Programs Through Data Structures 4 Software Design with UML • Programmers use various graphical notations to represent analysis and design decisions • UML: Unified Modeling Language – Dominant graphical scheme currently used in objectoriented software development • An excellent and free UML authoring tool is available at http://argouml.tigris.org/ Fundamentals of Python: From First Programs Through Data Structures 5 UML and Modeling • UML diagrams come in handy during the initial phases of software development – Help programmer visualize, or model, the interactions of human users with proposed system, relationships among its classes, and interactions among its objects • UML includes diagrams for almost any occasion – For example: • Class diagrams • Use case diagrams • Collaboration diagrams Fundamentals of Python: From First Programs Through Data Structures 6 Use Case Diagrams • A use case is a narrative, in English, of the steps a user takes to perform a single action Fundamentals of Python: From First Programs Through Data Structures 7 Use Case Diagrams (continued) • Use cases should include narratives of exceptional conditions and corresponding responses Fundamentals of Python: From First Programs Through Data Structures 8 Use Case Diagrams (continued) • Use case diagrams in UML translate narratives of use cases into a pictorial representation Fundamentals of Python: From First Programs Through Data Structures 9 Use Case Diagrams (continued) • Use cases and use case diagrams enable the programmer to accomplish several things: – Result in a precise statement of the functional requirements of the software system, in other words, the “what it does,” from the users’ perspective – Serve as the basis for writing user documentation, in the form of manuals and online help systems for the software – Allow the programmer to determine which classes need to be chosen or developed to realize the requirements of the system Fundamentals of Python: From First Programs Through Data Structures 10 Class Diagrams • During the discovery of classes for a system, their relationships can be modeled with class diagrams – The simplest such diagrams show a relationship of association between two classes Fundamentals of Python: From First Programs Through Data Structures 11 Class Diagrams (continued) • Associations do not tell us how classes are related – Programmer can also specify a role that a class plays in relation to another Fundamentals of Python: From First Programs Through Data Structures 12 Class Diagrams (continued) Fundamentals of Python: From First Programs Through Data Structures 13 Class Diagrams (continued) Fundamentals of Python: From First Programs Through Data Structures 14 Class Diagrams (continued) • The arrows representing directed associations can be dropped in favor of using edges with markers that indicate aggregation or composition Fundamentals of Python: From First Programs Through Data Structures 15 Collaboration Diagrams • The attributes and operations of a given class are often designed to fit into a sequence of operations that perform a particular task – The actors in these scenarios are software objects or instances of the system’s classes – A system function or task is broken down into a set of method calls on objects, and coordinating these becomes the focus of design • The interactions among objects can be documented in a collaboration diagram Fundamentals of Python: From First Programs Through Data Structures 16 Collaboration Diagrams (continued) Fundamentals of Python: From First Programs Through Data Structures 17 From Collaboration Diagram to Code Fundamentals of Python: From First Programs Through Data Structures 18 From Collaboration Diagram to Code (continued) Fundamentals of Python: From First Programs Through Data Structures 19 Inheritance • Subclassing helps eliminate redundant code in similar classes • Inheritance relationship between classes is shown with an outlined arrowhead in a class diagram Fundamentals of Python: From First Programs Through Data Structures 20 Documentation • In this section, we examine ways to make documentation more systematic and informative • You will also learn about a tool, pydoc, which you can use to generate documentation that can be viewed with a Web browser Fundamentals of Python: From First Programs Through Data Structures 21 Writing APIs • API: Application Programming Interface – Interfaces for a programming language’s built-in resources – Most interfaces also include documentation • Browse the API for the current version of Python at Python’s Web site (http://docs.python.org/) • Access information about an API from within a Python shell by using the help function Fundamentals of Python: From First Programs Through Data Structures 22 Writing APIs (continued) • What information should an API include? – Module: its filename, a brief statement of its purpose, a summary of the resources that it includes – Class: name of class and superclass, a brief statement of its purpose • Might also include a short list of the operations available to the client (the class’s interface) – Method: its header, a brief statement of what it does (not how it does it), the types of arguments it expects, and the type of value it returns – Function: same information included for a method Fundamentals of Python: From First Programs Through Data Structures 23 Revisiting the Student Class Fundamentals of Python: From First Programs Through Data Structures 24 Revisiting the Student Class (continued) Fundamentals of Python: From First Programs Through Data Structures 25 Revisiting the Student Class (continued) • Most of the methods in the Student class are accessors – Accessors are generally the easiest to document, especially those that expect no arguments • A simple statement about the type and meaning of the value returned by the method usually suffices • setScore is the only mutator method • getScore and setScore call for further attention – What happens if the reader misses the fact that the positions of the scores are counted from 1, not 0? Fundamentals of Python: From First Programs Through Data Structures 26 Preconditions and Postconditions • Precondition: Statement of what must be true before a method is invoked if it is to run correctly – Usually describe the state of any parameters and instance variables that a method is about to access • Example: Fundamentals of Python: From First Programs Through Data Structures 27 Preconditions and Postconditions (continued) • Postcondition: Statement of what will be true after the method has finished execution – Describe the state of parameters and instance variables that the method has changed • Example: Fundamentals of Python: From First Programs Through Data Structures 28 Enforcing Preconditions with Exceptions • Preconditions in documentation do not prevent users from violating them – Avoid problems by guaranteeing that an exception will be raised if a precondition is violated • Syntax for raising an exception: • Must document that exceptions may be raised: Fundamentals of Python: From First Programs Through Data Structures 29 Enforcing Preconditions with Exceptions (continued) • A programmer should try to raise a type of exception that is specifically related to the kind of condition being enforced Fundamentals of Python: From First Programs Through Data Structures 30 Web-Based Documentation with pydoc • Programmer-authored documentation is always available in the Python shell: … Fundamentals of Python: From First Programs Through Data Structures 31 Web-Based Documentation with pydoc (continued) • Documentation can be viewed in a Web browser – pydoc tool allows programmer to generate documentation from a module in form of a Web page • To create this page: – Open a terminal window and navigate to the directory that contains your Python source file • Example: student.py – At the terminal command prompt, run: pydoc –w student > student.html Fundamentals of Python: From First Programs Through Data Structures 32 Testing • A great deal of time, effort, and money is spent trying to prevent software errors from ever happening • In this section, we examine testing, the discipline that searches for program errors and builds confidence that software works correctly Fundamentals of Python: From First Programs Through Data Structures 33 What to Test • There are several features of a program’s behavior that we might want to consider: – – – – Is the program user friendly? Is the program robust? Is the program reliable? Does the program provide acceptable performance? • In this section we confine our attention to a more minimal sense of program correctness – A correct program produces the expected outputs when operating on inputs that fall within specified limits Fundamentals of Python: From First Programs Through Data Structures 34 Three Approaches to Choosing Test Data • Haphazard: Bang on the program with a few inputs until it breaks, fix bugs, and call it correct – Not very effective • Black-box: Partition inputs in clusters of equivalent data (if program works correctly on a set of values from a cluster, it works well for all values in cluster) – Also test for values on boundaries between clusters – Easy to overlook some clusters – Number of clusters can be so large that we cannot possibly consider them all Fundamentals of Python: From First Programs Through Data Structures 35 Three Approaches to Choosing Test Data (continued) • White-box: Attempt to concoct test data that exercise all parts of our program – You examine the code closely and then formulate the test data, but the task can be difficult • Code coverage • Tip: Combine black-box testing with white-box testing Fundamentals of Python: From First Programs Through Data Structures 36 When to Test • Four points during coding at which test data can be used: – Unit testing: Write code that instantiates an object of the desired type and then run a series of methods that subject it to a thorough workout – Integration testing: After classes have been tested in isolation, confirm that they work together properly – Acceptance testing: Test under conditions identical to those in which it will eventually be used – Regression testing: Keep test data for later use (e.g., to test modifications to program) Fundamentals of Python: From First Programs Through Data Structures 37 Proofs of Program Correctness • Testing cannot actually demonstrate the program’s correctness • We can prove that a program is correct in a strictly mathematical sense – Quite tedious – May lead to invalid proofs if not enough mathematical background • Can we automate the process of determining program correctness? – It is impossible, not just difficult, to write a program that can solve the halting problem Fundamentals of Python: From First Programs Through Data Structures 38 Unit Testing in Python • Kent Beck developed one of the first tools for the unit testing of classes (for Smalltalk) • Beck and Erich Gamma wrote junit and pyunit • A unit test consists of a set of test cases for a given class – Each test case is a method that runs tests on an individual method in the class – The tests take the form of assertions • A test suite can be run whenever a change is made to the class under development Fundamentals of Python: From First Programs Through Data Structures 39 Unit Testing in Python (continued) Fundamentals of Python: From First Programs Through Data Structures 40 Unit Testing in Python (continued) Fundamentals of Python: From First Programs Through Data Structures 41 Unit Testing in Python (continued) Fundamentals of Python: From First Programs Through Data Structures 42 Unit Testing in Python (continued) Fundamentals of Python: From First Programs Through Data Structures 43 Unit Testing in Python (continued) Fundamentals of Python: From First Programs Through Data Structures 44 Unit Testing in Python (continued) • The TestCase class includes a significant number of methods that you can use to make assertions about your code Fundamentals of Python: From First Programs Through Data Structures 45 Unit Testing in Python (continued) • Although unit tests are ideal for testing individual classes, to a certain extent they can also be used during integration testing • By developing and running a good unit test for each class, programmer can focus on writing code and leave the testing to an automated assistant • Test-driven development encourages detection of errors early in the coding process and increases the likelihood of thorough white-box testing Fundamentals of Python: From First Programs Through Data Structures 46 Summary • UML is the leading graphical notation for depicting the structure and behavior of OO software systems – A use case describes the steps performed during an single interaction of a user with a SW system – A class diagram shows the relationships among the classes of a software system – A collaboration diagram shows interactions among objects required to complete a task in a SW system • Preconditions and postconditions form the subject of an agreement between the author of a method and its client Fundamentals of Python: From First Programs Through Data Structures 47 Summary (continued) • You can enforce a precondition by raising an exception if that precondition is not satisfied • Complete documentation of a method includes information about any preconditions, postconditions, and exceptions that it might raise • Generate Web-based documentation for a Python resource by running the pydoc tool • Black-box testing: Programmer selects test data that produce expected results for normal inputs and abnormal inputs Fundamentals of Python: From First Programs Through Data Structures 48 Summary (continued) • White-box testing: Select test data that exercise all of the possible execution paths in a given resource • Unit test: Subjects a class to a thorough workout – Pyunit provides a tool for automating unit tests • Integration testing examines the behavior of cooperating classes that have been unit tested • Acceptance testing subjects a software system to examination under realistic conditions • Regression testing is performed when any part of a software system is repaired or extended Fundamentals of Python: From First Programs Through Data Structures 49