introduction to software engineeringzeil/cs350/latest/4x3.pdf · 5. apply the mutator/accessor...

630
CS350 Introduction to Software Engineering May 1, 2020

Upload: others

Post on 20-May-2020

17 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

CS350Introduction to Software Engineering

May 1, 2020

Page 2: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

CS350 OutlineSpring 2020

1 Introduction 01/12/2020 - 01/18/2020Overview

This module introduces you to the course organization, policies, and mechanics. We’ll review the structure of the course website and give you an opportunity toget set up for the semester to come.

We’ll take a brief look at the major themes and areas of emphasis that you can expect to hear more about through the coming semester.

Objectives

1. Identify the requirements, protocols, and policies for the online course

2. Use the selected technology tools for communication and collaboration

3. Discuss the course themes and their relation to software development.

Relevance

An understanding of the tools used in an online course is fundamental in becoming a successful online learner. It is also important to identify the expectationsfor participation, assignment submission, and the time management skills required in the online format.

You can expect that professional software development will be quite different from typical academic programming assignments. This course will emphasize thetools and techniques that developers use on a daily basis, with an emphasis on automating best practices of software engineering.

1. Read the syllabus.2. Read the communications policy.

3. Course Structure and Policies

4. Account Setup

Page 3: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

5. What Makes Software Development Difficult?

In your recitation section

1. Recitations will not meet this week. However, the recitation next week requires some preparation in advance of your scheduled session. You should readthrough the expectations this week.

2 The Software Development Process 01/19/2020 - 01/25/2020Overview

Every development organization settles into a process that they use to produce new software. Although the component activities are largely the same, differentprocesses place different levels of emphasis on the components and arrange those components differently.

We’ll look at the more common and the more influential models for software development processes and will examine the interaction between the developmentmodel and the organization and composition of development teams.

Objectives

1. Discuss the phases and component activities of software development

2. Assess the likely impact of popular software process development models on a project

3. Discuss common team organizations and roles in software development

Relevance

A development model establishes the context in which we can consider more specific best practices. At the same time, the more modern and trendydevelopment models take for granted that team members will have a high level of familiarity with common best practices.

Process Models

1. Tsui, Ch.42. Software Development Process Models

3. Lab: Secure Shell Keys

4. See website for assignment.

Staffing

Page 4: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. Team Organization

Design

1. High-Level Design: A Quick Overview

In your recitation section

1. Network Conferencing: Google Meet 01/21/2020

3 Requirements 01/26/2020 - 02/01/2020Overview

We will look at the processes of eliciting and analyzing requirements, and at common forms of documents for recording them. We will look at how thesedocuments vary depending on whether we are doing requirements analysis “up front” or incrementally. We will discuss the characteristics that contribute to thequality of requirements statements.

Objectives

1. Recognize common forms of requirements documents2. Discuss quality characteristics for requirements3. Write a requirements document in an industry-standard format.

Relevance

All software development projects begin with a statement of requirements. All subsequent software construction must refer back to those requirements. It istherefore essential that all developers be able to read and understand requirements documents, even if they were not actively engaged in writing thosedocuments.

Eliciting and Writing Requirements

1. Wiegers, ch 6, 7, 10, 112. Eliciting Requirements3. Writing Requirements

In your recitation section

At the end of the week

Page 5: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. Project Phase 1: Software Requirements Specification Start work on phase 1 of the project. Note: Due dates for project phases are collected in a separate section near the bottom of this outline.

4 Software Construction 02/02/2020 - 02/08/2020Overview

Software construction is the term used for the development activities that follow requirements and lead up to the final system and acceptance tests. In thismodule, we will take a high-level look at the component activities of software construction and will discuss some of the critical decisions that need to be madeat the start of construction.

Students will begin the process of building their personal development environment by installing and practicing with a modern IDE (Integrated DevelopmentEnvironment).

Objectives

1. Identify and discuss the constituent activities of software construction2. Discuss issues associated with these activities3. Review the contributions and features of IDEs in construction activities

Relevance

This module sets the stage for the exploration of more detailed construction topics to follow in the remainder of the course.

Clean Coding

1. Martin, ch 2, 3, 6, 7, 102. Clean Coding3. CS382, Sections 1-3 (Read lecture notes and do the labs.)4. Integrated Development Environments5. See website for assignment.

Organizing Incremental Construction

1. Cohn, ch 1-3, 72. User Stories3. Shore, ch. 8, Stories

In Your Recitation Section

1. . Recitations do not meet again until explicitly noted in the Project schedule below.

Page 6: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

5 Unit Testing 02/09/2020 - 02/22/2020Overview

In this section we will review the basic principles of unit testing, and then we will look at the problem of automating the testing oracle, the procedure ofdetermining when our code has passed or failed each test.

This will lead us to the world of modern Unit test frameworks, which seek to make running tests so effortless that there is no longer any excuse to defer testing.

On the cutting edge of testing practice, we will look at mock objects as a means of further automating our tests.

Objectives

1. Discuss the position of testing in an overall verification and validation context.2. Discuss the varying scopes and goals of testing.3. Discuss the activities comprising testing and the role of automation in supporting those activities.4. Apply *Unit frameworks.5. Apply the mutator/accessor strategy for ADT testing.6. Discuss the use of mock objects in unit testing.

Relevance

Unit testing has always been seen as a critical part of software construction, but modern best practices place more emphasis on it than ever. “Test first” is amantra in modern software development, and common practice integrates testing so tightly into the build process that it’s more trouble to avoid tests than to re-run them at each step.

V&V

1. Verification and Validation2. Lab - Eclipse3. Testing4. Why Do We Test?5. Choosing Tests6. Testing the F16 Fighter

Self-Checking Test Drivers

1. Good Unit Tests2. Automating the Testing Oracle3. JUnit Tutorial

Page 7: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4. (optional) Google Test Primer

5. Lab: Unit Testing6. Testing ADTs

7. See website for assignment.

Test-Driven Development

1. Martin, ch 9

2. Test-Driven Development

Stubbing and Mocking

1. Stubs and Mocking2. Mocks Aren’t Stubs3. Google C++ Mocking Framework for Dummies

6 Version Control 02/23/2020 - 03/01/2020Overview

Version control is concerned with managing the history of changes made to the software by the development team. A good version control system offers a teamcontrol over the history, exploration, and collaboration on a project. We’ll look at the issues and approaches to local, centralized, and distributed version control,and explore how to work with a distributed version control system from an IDE.

Objectives

1. Discuss the issues and problems involved in collaborative development of software

2. Discuss the major types of version control (local, centralized, and distributed) and how team conflicts are resolved in each

3. Discuss the concept of branches and their impact on software development strategy

4. Apply a distributed or centralized version control system

5. Manage a repository within a forge environment

Relevance

Page 8: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Version control has rescued many a project from utter disaster of having lost or destroyed critical code. Probably the only practice that has done so more oftenwould be regular backups. But version control is also central to managing collaboration among team members, allowing confidence that developers workingindependently need not fear overwriting or interfering with one another’s work.

Version Control

1. Version Control2. Masters & Blum, Chapter 43. Local Version Control (sccs, rcs)4. Centralized Version Control (CVS, Subversion)5. Understanding Git Conceptually6. Distributed Version Control7. Breaking the Build

8. Lab: Version Control with Git

9. Forges

10. See website for assignment.

Exam

1. Midterm exam 03/01/2020 - 03/03/2020

7 Build Management 03/01/2020 - 03/17/2020Overview

A build manager has the task of performing any automated steps required to rebuild a software project after programmers have made changes. We will look atthe primary models for build management, file dependencies and task dependencies, and the most commonly used managers for each model. We’ll also look athow to replace an IDE’s built-in builder with a more flexible manager.

Objectives

1. Discuss the role of build managers in supporting a project2. Discuss the limitations of the default build managers provided with IDEs3. Discuss and assess the impact of the major forms of dependency management in builds4. Apply a common file dependency manager (make) and task dependency manager (ant/maven/gradle)

Relevance

Page 9: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Modern projects now rely on build managers for much more than just the basic operations of compiling and linking. Build managers are also called upon to runtests, to prepare software packages for deployment, to deploy them, and to prepare project reports and post those reports to project web sites. These demands gofar beyond the capabilities of the simple manager included in your IDE. Used properly, a build manger can save a team a lot of tedious work.

1. Build Managers

2. See website for assignment.

3. File Dependencies: make

4. Task Dependencies: ant5. Managing Builds with Maven

6. Gradle guide: Creating a New Gradle Build

7. Gradle guide: Building Java Applications8. Gradle guide: Building C++ Executables9. Task Dependencies: Gradle

10. Lab: Building with Gradle11. See website for assignment.

(Optional) Maven & Ant In Detail

1. Ant Tutorial2. Maven in 5 Minutes

8 Configuration Mgmt 03/18/2020 - 03/28/2020Overview

Software Configuration Management (SCM) addresses a wide variety of issues in the development of software. These include version control, studied earlier,but also the problems of coping with portability to multiple target platforms and the incorporation of externally developed code libraries into a project. We’llexplore these new issues of SCM and will look at how configuration management tools can aid in keeping all the components of a project compatible with oneanother.

Objectives

1. Discuss issues in supporting multiple target platforms2. Discuss issues involved when incorporating 3rd party libraries as software components3. Discuss the role of configuration management tools4. Apply a common configuration management tool (maven/tvy)

Page 10: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

5. Discuss the role of repositories

Relevance

With an increasingly rich universe of open-source and commercial libraries available, development teams are increasingly encouraged to avoid wasting effortby resolving problems already solved by someone else. Discovery of useful libraries can be difficult, however, and the possibility that a useful library may itselfincorporate still other libraries raises the very real problem of inconsistency among a project’s components.

Configuration Management

1. Software Configuration Management2. Appleton, Streamed Lines through "Using the Branching Patterns3. Managing Third-Party Libraries4. Managing Code Variants

9 Documentation 03/29/2020 - 04/04/2020Overview

In this module, we will review some of the basic lessons on source code documentation that you may have learned as beginning programmers and will considerhow well they translate to more professional practice. In accord with current best practice, we will look more closely at API documentation and the tools forbuilding and maintaining that documentation. We will also look at some common project reports and how they might be posted to a project website.

Objectives

1. Discuss forms and roles of code documentation2. Discuss common API documentation tools3. Apply a common API documentation generator (Javadoc/Doxygen)

Relevance

Modern practice places far less emphasis on source code documentation than beginning programmers are often led to believe. At the same time, developers arecommonly expected to conform to a higher standard in preparing API documentation and project reports.

1. Martin, ch 42. McConnell, Ch. 323. Documentation and Documentation Generators4. Project Reports & Websites

Page 11: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

10 Analysis Tools 04/04/2020 - 04/11/2020Overview

This module will examine some of the validation tools that lie outside the realm of testing, including analysis for dead code, for overly complex code, and forviolation of coding standards and practices.

Also, with our now content-rich, automated builds, we will examine the practice of continuous integration as a means of keeping project status information upto date.

Objectives

1. Discuss the differences between dynamic and static analysis2. Apply code coverage tools3. Apply static code analysis tools and interpret their results4. Apply a continuous integration framework to manage report generation.

Relevance

Many clients require the use of code analysis tools on delivered code, treating the reports from these tools as part of the acceptance test for the system.Developers need to understand both the abilities and limitations of the analysis performed by these tools. With so many reports being produced by projects,automating not just the build but the launching of new builds is an increasingly common practice.

Static & Dynamic Analysis

1. Program Analysis Tools2. Continuous Integration3. Continuous Integration Lab

11 System and Regression Testing 04/12/2020 - 04/18/2020Overview

System testing often involves inputs that are hard to supply or outputs that are hard to capture (e.g., graphics on a screen). Some regression tests can face thesame problem. We’ll examine the possibilities of automating tests at this level to a degree similar to what we achieved earlier with unit testing.

Objectives

1. Discuss problems introduced when testing at the system level

Page 12: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2. Discuss tools for testing GUI code3. Discuss the role of bug/issue tracking in a development process4. Apply an issue tracking system in a team project

Relevance

The rise of GUI interfaces as the most common way for users to interact with programs created a huge problem for system testing that, decades later, is still asource of difficulty for development teams. Developers need to know what can be done automatically about this and how they can design or plan around theproblems when automated solutions are unworkable.

1. System Testing2. Regression Testing3. Issue Tracking

12 Agile Methods 04/19/2020 - 04/27/2020Overview

Agile development is a set of practices centered on an incremental development model. Agile methods are threatening to topple the Waterfall as the mostcommonly used development process model.

We will explore the principles and practices that comprise agile development. We will see how many of the practices studied in the earlier modules lie at theheart of agile practice. We will look at some of the primary development models within the agile movement.

Objectives

1. Discuss the conflict between incremental and “up front” models2. Assess the impact of incremental models on a development project3. Discuss the philosophy and components of agile models4. Discuss the impact of agile models and requirements elicitation

Relevance

Agile development is not only a set of development practices and process models, but also a social/political movement in the world of software development.

The Agile Manifesto calls for non-technical managers to properly respect software developers by adopting a hands-off attitude to technical decisions. This callwould be unforgivably arrogant if the Manifesto did not also call for developers to demonstrate their professionalism by knowing and adopting the profession’sbest practices, independent of any mandates from management requiring them to do so.

1. The Agile Manifesto & Twelve principles

Page 13: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2. Agile Methods3. Beck, Ch 74. Extreme Programming (XP)5. Scrum Guide6. Scrum7. Is Agile for Amateurs?8. Trends in Agile

13 ProjectPhase 1

1. Project Phase 1, Requirements Specification 02/02/2020 - 02/13/2020

Phase 2

1. Sign up for project teams 02/12/2020 - 02/13/20202. Project Phase 2, stories 02/14/2020 - 02/24/2020

Phase 3

1. Project Phase 3 02/25/2020 - 03/29/20202. Project: Design Brainstorming 02/25/2020 - 02/25/20203. Optional phase 3 progress meetings (in your recitation section) 03/24/20204. Project phase 3 review meetings (in your recitation section) 03/31/2020

Phase 4

1. Project Phase 4 03/30/2020 - 04/19/20202. Project phase 4 review meetings 04/21/2020

14 Special Events and Dates1. MLK Day 01/20/2020 - 01/20/20202. Midterm exam 03/01/2020 - 03/03/20203. Spring Break 03/09/2020 - 03/14/20204. Final exam 05/02/2020 - 05/04/2020

Page 14: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

15 PreambleGeneral Information

Below are the modules that comprise the course content.

Each module consists of a series of activities.

Not every assigned activity requires you to submit something for grading. Nonetheless, you are expected to do them all.

Do not skip or delay doing the labs just because they are ungraded. Most of them introduce skills (and sometimes set up specific data) used in asubsequent assignment or in the project.

If no due date is specified, you are supposed to complete the assigned activity by the end of the final day allotted for that entire module.

Where a due date is given with no time, you have the entire day (until 11:59:59PM ET of the due date).

15 PostscriptAll times in this schedule are given in Eastern Time.

Symbol KeyLecture:Slides :Event or important dateReadDo lab:Assignment:Take theDo:In your recitation section:Under construction:

16 PresentationTopics Lectures Readings Assignments & Other Activities

Page 15: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Topics Lectures Readings Assignments & Other Activitiestopics lecture slides event exam video project construct text exam asst selfassess exam activity lab recitationDocument Kind Prefixlecture Read lecture notes:eventexam Take the exam:lab Do:asst Do assignment:reading Read (optional):© 2015-2020, Old Dominion Univ.

Page 16: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

CS 350 Introduction to Software Engineering (Spring 2020)Steven J. Zeil

Last modified: Jan 7, 2020

Contents:1 Course Description

1.1 Instructor1.2 Course Pre-requisites1.3 Meeting Times and Delivery Method

2 Basic Course Information2.1 Required Text2.2 Resources for Getting Started2.3 Computer Accounts2.4 Hardware & Software Requirements

3 Course Policies3.1 Recitation Attendance3.2 Due Dates and Late Submissions3.3 Academic Honesty3.4 General University Policies3.5 Grading

4 Assignment Grading5 Exams6 Topics

6.1 Objectives6.2 Expectations

7 Educational Accessibility

Website: ../../

1 Course DescriptionThis course explores the software development process. It will discuss the major activities common to software development processes, and some of the ways inwhich those activities are organized and managed.

Page 17: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Heavy emphasis will be placed on the day-to-day skills required during software construction. The course will explore lessons and tools offered by the majorsuccessful open-source software efforts.

The course requires each student to participate as a member of a team in a significant team project. Each student will be required to demonstrate proficiency inseveral software development tools.

1.1 Instructor

Steven Zeil E&CS 3208(757) 683-4928 [email protected]

Please make sure to include the course name “CS350” in the subject line of any email related to this course.

1.1.1 Office Hours

Office hours are posted online at http://www.cs.odu.edu/~zeil/officehours/

General questions about course content and reports of website problems should normally be asked in the Forums on Blackboard or via email.

Questions about grades, how to solve assignments and other graded activities must be sent to [email protected], not posted in Forums.

For more discussion on course communications, please refer to the Communications policy.

1.2 Course Pre-requisitesCS 252 (Introduction to Unix for Programmers)CS 330 (Object-Oriented Programming and Design), orCS 361 (Advanced Data Structures and Algorithms)

Students who have not taken CS 330 are encouraged to take CS 382 (Introduction to Java) as a pre-requisite or, at the very least, to work throughthat courses’s website during the first few weeks of the semester.

1.3 Meeting Times and Delivery MethodStudents must register for both a lecture section and a recitation section.

% else

* The primary purpose of the recitation is to allow project teams to meet with the instructor for periodic evaluation of their progress.

Page 18: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

* For the purpose of these meetings, it will be important that students be seated at or connected to their chosen development machine and prepared to demonstrate aspects of the project under review. * There will also be a small number of earlier recitations devoted to learning the conferencing tools that will be used in the later meetings. Recitation sections will not meet every week, but the scheduled meetings are mandatory. During weeks when recitations are not scheduled, project teams may wish to use that time for their own meetings. As necessary, the instructor may announce open "help" sessions during the recitation time periods to provide aid on assignments and labs. Attendance at these sessions will be optional.

2 Basic Course Information2.1 Required TextReadings from the Internet will be assigned from the course website.

2.2 Resources for Getting StartedODU Online Student Orientation

2.3 Computer AccountsStudents will need two network accounts to participate in this class:

An ODU ITS account. This is the account associated with your @odu.edu email. It will allow you to log into the course’s Blackboard site. All ODUstudents automatically receive this account, though you may need to activate yours, if you are new to ODU.

An account on the CS Dept. network. This will be used for access to the CS dept computing resources, and for accessing and submitting assignments. Youmay have a CS account already if you were registered for a CS class last semester. If not, the account setup can be initiated at http://www.cs.odu.edu/ byclicking on “Account Creation” under “Online Services”.

2.4 Hardware & Software Requirements

Page 19: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Students will need frequent access to a PC capable of hosting software development activities or of connecting remotely to CS Dept servers where suchactivities can be performed.

Students will be attending network conferences requiring the use of a microphone. Webcams are optional.

For both remote access to CS Dept servers and for network conferencing, a good-quality internet connection is important.

The course will introduce students to a wide variety of software packages. All of these are open-source, free software, but students will need to install some ofthese on their chosen development machine (whether their own PC or in their account on the CS network).

3 Course Policies3.1 Recitation AttendanceProject review sessions will be scheduled for selected weeks during the recitation periods. Attendance at these is mandatory. Failure to attend will result insubstantial grade penalties for that portion of the project.

Attendance at other scheduled recitation sessions, as announced in the course outline, is also mandatory. Failure to attend may result in grade penalties.

3.2 Due Dates and Late SubmissionsLate assignments and make-up exams will not normally be permitted.

Exceptions to this and other grading policies will be made only in situations of unusual and unforeseeable circumstances beyond the student’s control.Arrangements must be made prior to the due date in any situations where the conflict is foreseeable.

“I’ve fallen behind and can’t catch up”, “I’m having a busier semester than I expected”, or “I registered for too many classes this semester” are not grounds foran extension.

3.3 Academic HonestyEverything turned in for grading in this course must be your own work, or, for team projects, the work of your own team. Opportunities for teamwork will beclearly identified as such.

Students are expected to conform to academic standards in avoiding plagiarism.

Among other things, this means that if you use ideas found on the internet (outside of the course website) in your answers to an assignment or examquestion (including when coding!), you must cite your sources appropriately.

Page 20: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

If you use text directly taken from such sources you must appropriately designate the quoted material as such.

The instructor reserves the right to question a student orally or in writing and to use his evaluation of the student’s understanding of the assignment and of thesubmitted solution as evidence of cheating.

Students who contribute to violations by sharing their code/designs with others may be subject to the same penalties. Students are expected to use standard Unixprotection mechanisms (chmod) to keep their assignments from being read by their classmates. Failure to do so will result in grade penalties, at the very least.

This policy is not intended to prevent students from providing legitimate assistance to one another. Students are encouraged to seek/provide one another aid inlearning to use the operating system, in issues pertaining to the programming language, or to general issues relating to the course subject matter.

Student discussions should avoid, however, explicit discussion of approaches to solving a particular programming assignment, and under nocircumstances should students show one another their code for an ongoing assignment, nor discuss such code in detail.

Violations of this policy will be reported to the Office of Student Conduct and Academic Integrity for consideration for punitive action.

3.4 General University PoliciesThe ODU Catalog lays out a wide variety of University policies that are binding upon both students and faculty. All students are required to abide by these.

3.5 Grading

Assignments 15%Semester Project 45%

Midterm Exam 15%Final Exam 25%

Individual Assignments (15% in total) and individual Semester Project Phases (50% in total) will not necessarily be equally weighted.

Grading is normalized.

4 Assignment GradingIndividual assignments will be turned in through the CS submission system, rather than through Blackboard–more information is available here. Most of theassignments will be graded by an automatic grader. The results will be sent to your email account. Unless the assignment explicitly states otherwise, you may

Page 21: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

submit a total of three times; the instructor will take the last of the marks, although you may request that your score be “rolled back” to an earlier one. You mayNOT submit after viewing the sample solution.

5 ExamsThe Midterm Exam and Final Exam will be administered online via Blackboard.

6 TopicsTopics will include:

Software development processes, including the waterfall, unified OO, and extreme programming modelsRevision management: local, centralized, & distributed approachesConfiguration Management: project configuration, managing external librariesDocumentation toolsBuild ManagementTest-driven developmentUnit & Integration Testing: coverage, self-checking, mocking, designing for testabilityDebugging: local & remote, monitors, reverse debuggingRegression TestingIssue trackingSoftware Forges & Repositories

6.1 ObjectivesStudents completing this course should be able to:

Demonstrate an understanding of the overall strategy of software development:

Discuss the phases and component activities of software development

Assess the likely impact of popular software process development models on a project.

Discuss common team organizations and roles in software development.

Work with software requirements documents

Read common forms of requirements documents

Page 22: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Write at least one standard form of requirements document

Apply requirements to guide the subsequent construction of software

Apply best practices in collaborative software construction

Discuss the issues and problems involved in collaborative development of software.

Evaluate the suitability of alternative best practices for a software construction project.

Support common best practices of via a modern IDE and associated tools

Apply a variety of software measurement and estimation techniques.

6.2 ExpectationsStudents will engage in team projects in this course. Students are expected to actively participate in and contribute to their teams, and this engagement with theteam will be part of the grade.

7 Educational AccessibilityOld Dominion University is committed to ensuring equal access to all qualified students with disabilities in accordance with the Americans with DisabilitiesAct. The Office of Educational Accessibility (OEA) is the campus office that works with students who have disabilities to provide and/or arrange reasonableaccommodations.

If you experience a disability which will impact your ability to access any aspect of my class, please present me with an accommodation letter from OEAso that we can work together to ensure that appropriate accommodations are available to you.

If you feel that you will experience barriers to your ability to learn and/or testing in my class but do not have an accommodation letter, please considerscheduling an appointment with OEA to determine if academic accommodations are necessary.

The Office of Educational Accessibility is located at 1021 Student Success Center and their phone number is (757) 683-4655. Additional information isavailable at the OEA website http://www.odu.edu/educationalaccessibility/

Page 23: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

CommunicationsSteven Zeil

Last modified: Dec 21, 2019

Contents:1 So many options2 General Rules for On-line Communications

2.1 Public and Private Communications2.2 Etiquette in Email and Other Written Communications

3 Asking Good Questions3.1 Identification3.2 You Have to Give Information to Get Information3.3 Thou Shalt Not Paraphrase3.4 “Copy and Paste” is Your Friend!3.5 If I Ask You a Question, Answer It

1 So many optionsCommunication is a major concern in any course. Web courses make this a little trickier by reducing the options for face-to-face discussion.

Options for communications in this course include:

Email

to instructor

I generally try to answer all course-related email within 24 hours, sometimes dropping to 48 on weekends and holidays. I generally averagebetter than that.You can increase your odds of a speedy reply by making sure that “CS350” appears somewhere in the subject line of your email.

on group assignments, to members of your group

Email to the entire class should generally be avoided.

Discussion Board

Page 24: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Posts to Discussions will be visible to the instructor and the entire class.

Announcements

Only the instructor can send announcements.

Network Conferencing

Early in the semester, you’ll be learning how to use Google Meet as a network conferencing system. You can use this to meet the instructor during officehours or to set up meetings with team members during group assignments.

Office Hours

Yes, given that this is a Distance Course, many of you can’t come to campus to see me face-to-face. But I also offer options of meeting by telephone orvia network conferencing (Google Meet).

You can find my office hours here.

2 General Rules for On-line Communications2.1 Public and Private CommunicationsChoose a communications option that is appropriate to the nature of the discussion.

Some of the communications options that you have will open your discussion up to the entire class. Others will limit your discussion to the instructor or to yourteam on a group assignment.

In general, any conversation in which you discuss all or part of your solution to an individual assignment, even if you are only speculating onpossible solutions, should be limited to you and the instructor. Sharing such information with other students is a violation of the course’s policy onAcademic Honesty.

Use email or office hours for those kinds of questions.

Similarly, questions about your own grade on an assignment should be limited to a private communication with the instructor. In fact, if you were to try toask such a question in the public Discussion area, ODU privacy policies would prohibit the instructor from replying.

For group assignments, of course, you can consider opening up the conversation to include your team members. But you should not discuss specifics ofsolutions to group assignments with other teams.

Page 25: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

On the other hand, questions about the course subject matter or purely clarification questions about an assignment may be useful subjects for theentire class. These are good subjects for the Discussions area.

The instructor may, if he feels it is appropriate, copy an e-mailed question to the Discussions area so that the answer becomes available to everyone.

2.2 Etiquette in Email and Other Written CommunicationsStudents posting in the Discussions area or sending email to the instructor or to classmates are expected to conform to the norms for civility and respectfor ones’ classmates and instructors that are common to all on-campus speech and writing.

Students are also expected to conform to the norms of “netiquette”, for example, RFC 1855: Netiquette Guidelines . In particular:

Emotions are often hard to convey and easy to misunderstand in written text. Smileys and other emoticons can help (but don’t assume that attachinga :-) to an insult will make everything OK with the people reading your post.).

DON’T WRITE IN ALL CAPITALS or in all bold or, even worse, IN ALL BOLD CAPITALS. This is considered to be shouting, and mostpeople don’t like to be shouted at, whether in real life or on-line.

“Shooting the messenger” is seldom a good idea. In general, assume that people who take the time to reply to your posts are honestly trying to help.Getting mad at them and “flaming” back is counter-productive if you really want people to help you.

Replies to posts will often be short and to the point simply because the responder has limited time. Don’t mistake terseness for rudeness.

Many people who post questions and requests for help may have made very basic mistakes. If you omit the details of everything you thought of andchecked before making your post, don’t be insulted if someone replies with a very basic suggestion or a link to something that you have alreadyread.

Don’t “hijack” existing Discussions (threads) to talk about a topic different from the original poster’s topic. Start your own thread instead.

In an ordinary conversation, no one appreciates the person who barges in and insists on changing the topic of discussion. And if two groups ofpeople actually insist on trying to simultaneously carry on a discussion on two distinct topics within the same conversation, the result is usuallyconfusing to everyone.

3 Asking Good QuestionsWhether posted in Discussions or sent via email, a question is the beginning of a dialog. A well-prepared question will get you an informative answer quickly.A poorly-prepared one may get you irrelevant answers or may require several rounds of back-and-forth dialog, delaying your eventual answer by many hours oreven days.

Page 26: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

So it’s in your own self-interest to ask your question in a way that gets you the answer you need as quickly as possible.

3.1 IdentificationWho are you? : If you are sending me email, make sure your course login name or your real name appears somewhere in the message. I hate getting mail [email protected] saying “Why did I get such a low grade on question 5?” when I have no idea who this person is!

What course is this? : Again, if you are sending me a question via email, please remember to state which course you are asking about. I teach multiple coursesmost semesters.

For email, please put the course number (CS350) in the subject line. I configure my email reader to flag such messages for priority handling, giving you lesschance of being lost amid the daily flood of spam.

Use a clear and precise subject header.: In Discussions, your subject header helps people decide if your post is worth reading. It also helps people find priordiscussions that may have been relevant to later posts.

In e-mail, the subject line shares much the same purpose. Empty and short subject lines are also more likely to get tossed by autoamtic spam filters.

3.2 You Have to Give Information to Get InformationWhen you ask a question, you usually want an appropriate answer that will let you get past whatever difficulty you are having. So that answer needs to berelevant to your particular difficulty and tailored to your understanding of the course material.

I’m not psychic.

If you send me an email consisting of nothing more than “I’m stuck on this assignment.”, there’s really no way I can give you the kind of answer you are hopingfor. You need to tell me:

What part of the assignment are you stuck on?

What have you tried so far? (Be specific. If you’ve tried lots of things, tell me about your best attempt so far.)

What happened when you tried it?

If you don’t tell me those things, I’m just going to have to ask for that information, delaying the process of getting you the answer you want.

If you have an issue with a webpage, \emphasis{tell me the URL}. If a link is broken, \emphasis{tell me the URL of the page containing the link} and describethe location of the link. Don’t just tell me “the link to assignment 2 is broken”. I probably have a dozen different links to that assignment in different pages.

Page 27: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

To copy text from PuTTY or from a Linux or OS/X terminal, just left-click anddrag your mouse across text to select it. Your selected text is automaticallycopied to the clipboard, and you can paste it into an e-mail message or Forumpost.

3.3 Thou Shalt Not ParaphraseThere’s nothing more frustrating than getting a question like

“When I try to compile my solution to the first assignment, I get an error message. What’s wrong?”

Grrr. What was the (exact) text of the error message? Was this on a Linux or Windows machine? What compiler were you using? What compiler options didyou set? What did the code look like that was flagged by the message?

No, I’m not kidding. I get messages like this all the time. And it wastes my time as a question answerer to have to prompt for all the necessary information. Italso means a significant delay to the student in getting an answer, because we have to go through multiple exchanges of messages before I even understand thequestion.

The single most important thing you can do to speed answers to your questions is to be specific. I’m not psychic. I can only respond to the information youprovide to me.

Never, ever paraphrase an error message (“I got a message that said something about a bad type.”)Never, ever paraphrase a command that you typed in that gave unexpected results (“I tried lots of different compilation options but none ofthem worked.”, or, my personal favorite, “I tried everything.”)Never, ever paraphrase your source code (“I tried adding a loop, but it didn’t help.”)Never, ever paraphrase your test data (“My program works perfectly when I run it.”)

All of the above are real quotes. And they are not at all rare.

The problem with all of these is that they omit the details that would let me diagnose the problem.

3.4 “Copy and Paste” is Your Friend!

And it’s not all that hard to provide those details. Error messages can becopied and pasted into your message. The commands you typed and theresponses you received can be copied-and-pasted from your ssh/xtermsession into your message. Your source code can be copied-and-pasted orattached to the message.

Note that this information is almost always plain text. Unless you reallyneed to show me graphics, please don’t send me screen shots. They are often hard to read and often do not allow me to make the fine distinctions I need to tellwhat is going on. Keep in mind that raster graphics formats (gif, jpg, png, etc.) often look very different when rendered on screens with different resolutions.

Page 28: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.5 If I Ask You a Question, Answer ItI often respond to a student’s question with further questions of my own.

Teachers since Socrates have always done this, and students have always been annoyed at it. But who are we to argue with history?

Sometimes I do this to get more info I need, sometimes to guide the student towards an answer I think they should be able to find for themselves.

It’s surprising how often students ignore my questions and either never respond at all, respond as if my questions were rhetorical, or, if I have asked 2 or 3questions, pick the one that’s easiest to answer and ignore the rest.

This pretty much guarantees that the dialog will grind to a halt as I wind up repeating myself, asking the same questions as before, and some students go righton ignoring my questions, …

Page 29: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Course Structure and PoliciesSteven J. Zeil

Last modified: Dec 21, 2019

Contents:1 Syllabus2 Course Structure

2.1 Sessions2.2 Assignments2.3 Semester Project2.4 Exams

3 Course Pre-requisites4 Communications

4.1 Office Hours4.2 Course Forums

5 Important Policies5.1 Late Submissions5.2 Academic Honesty5.3 Grading

6 Course Themes6.1 Goals6.2 Areas of Emphasis

1 SyllabusAll students are responsible for reading the course syllabus and abiding by the policies described there.

2 Course Structure2.1 Sessions

Lectures: MWF 2:00-2:50PM, Dragas 1117Recitations: M 7:10-9:10PM, Tu 3:00-5:00PM (selected weeks)

Page 30: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Five phases:

Recitations

Recitations will be used for special topics and for meetings with teams once the semester project is underway.

They will not meet every week.Meetings will be on-line.

You will attend from your “development machine”.

2.2 AssignmentsIndividual assignments (3 attempts each). Assignments will include:

1. Command line exercises (e.g., SSH Keys)2. Tool Set up (e.g., Installing compilers and Eclipse)3. Programming in Java (e.g., Unit Testing)4. Version Control (e.g., Git)

This a non-exhaustive list.

2.3 Semester ProjectA moderately large program on which you will work in teams of 4-6 people.

Five phases:

1. Writing Requirements2. Planning for construction: writing user stories3. Early construction: build management, version control, story tracking, project website4. Middle construction: configuration management, documentation management, continuous integration5. Later construction: integration testing, analysis tools

In general, you will be evaluated upon process as much as upon you ability to produce working code.

The idea is to see if you have established a team process such that, if you had enough time, you would have eventually implemented the entire process.

2.3.1 Project Teams

I will assign you to a team, at random, for the first phase (Phase 1).

Page 31: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. Writing Requirements2. Planning for construction: writing user stories3. Early construction: build management, version control, story tracking,

project website4. Middle construction: configuration management, documentation

management, continuous integration5. Later construction: integration testing, analysis tools

Five phases:

1. Writing Requirements2. Planning for construction: writing user stories3. Early construction: build management, version control, story tracking,

project website4. Middle construction: configuration management, documentation

management, continuous integration5. Later construction: integration testing, analysis tools

You will choose your own teams for the remaining phases

Must be members of your recitation section.

2.3.2 Project and Recitations

The final three phases will be evaluated in part via a team meeting with theinstructor.

Held during recitation periodInstructor will ask questions about team’s overall progress.The instructor may direct questions to specific team members to besure that everyone shares an understanding of the project andrequired skills.

General rule is that if one member of a team does not knowsomething, that’s a mark against that person. If two peopledon’t know something, that’s a mark against the entire team.

At end of some meetings, you may receive a short test/assignment, which each team member must complete individually within a limited time period (aday or less).

2.4 ExamsMidterm & Final

Administered on-lineDates & times on the course calendar

Final exam is cumulative.

3 Course Pre-requisitesCS 252 (Introduction to Unix for Programmers)

Page 32: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

and

CS 330 (Object-Oriented Programming and Design), orCS 361 (Advanced Data Structures and Algorithms)

Students who have not taken CS 330 are encouraged to take CS 382 (Introduction to Java) as a pre-requisite or, at the very least, to workthrough that course’s website during the first few weeks of the semester.

4 CommunicationsContact Info

Steven Zeil E&CS 3208(757) 683-4928 [email protected]

Important: The course name “CS350” should appear in the subject line of all course-related email.

Forums are also available on Blackboard for general discussions.

4.1 Office Hoursif _kennedy

My general office hours are available at https://www.cs.odu.edu/~tkennedy/. Instructions for scheduling a formal appointment are listed here. Note that myoffice hours include both live and web-conference based appointments.

Office hours are posted online

Available from http://www.cs.odu.edu/~zeil/officehours/

Meeting modes:

face to face in my officeNetwork conferencing (Google Meet)Telephone

4.2 Course Forumsthe Hallway

for general discussion of course topics

Page 33: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

no discussion of assignment solutions!the Janitor’s Closet

reports of site issues, broken links, missing or incorrect web pages, etc.

5 Important Policies5.1 Late Submissions… are not normally accepted. Exceptions may be made in cases of

documented emergenciesarranged prior to the due date when possible.

Extensions to due dates will not be granted due to

difficulties “porting” from one system to anothertransient system crashessystem overloaded

5.2 Academic HonestyODU is governed by a student honor code.

Everything you turn in for grading must be your own work.Students are expected to conform to academic standards in avoiding plagiarism.Detailed policy statement is in the syllabus.

Academic Honesty (cont)

Aiding a fellow student to copy someone else’s work (including your own) places you equally in violation.Includes leaving work world-readable on the computer system!

Failure to report observed violations of the honor code is also a violation.Aiding a fellow student to copy someone else’s work (including your own) places you equally in violation.

Includes leaving work world-readable on the computer system!Failure to report observed violations of the honor code is also a violation.

5.3 Grading

Page 34: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Assignments: 15%Semester project: 50%

Midterm exam: 15%Final exam: 20%

6 Course ThemesQuestions

What is “Software Engineering”?

What is “Engineering”?

Is there “engineering” in software development?

6.1 GoalsLook at best practices from the open source world.What are the tools and techniques that developers use on a daily basis?Automate best practices.

Make it more trouble and more time consuming to do things wrong than to do them right.

6.2 Areas of EmphasisTeamworkTest-Driven Development (JUnit)

Build Management (Gradle)

Version Control (Git)Configuration Management (Gradle)Documentation Management (Javadoc)

6.2.1 Teamwork

Reaching and recording agreementCollaborating without conflict.Visibility & communication

Page 35: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

6.2.2 Test-Driven Development (TDD)

Exemplified by the philosophy of “write the tests first, then design and write the code.”

This is easily justified when fixing bugs. You need to have a test handy that shows the bug causing the program to fail, so that you can run it (again and again)while you try to fix the bug. How else will you know that you have it fixed?

But test-driven development is really about how to do the initial design. Programmers are often lazy. If they write the code first, they often skimp on the testingbecause that seems like too much work for code that they are “sure” is correct. (Remember, all programmers are optimists – they always believe that their codeis going to work “as soon as I fix this one bug”. The combination of unjustified optimism and laziness can be deadly!)

But if the tests are already there, and if it’s easy to run them (or, even better, hard not to run them – I’ll talk about that in just a moment), then programmers willactually do the testing on a regular basis.

And thinking about tests for special/boundary cases, etc., often helps you remember those cases when later doing the design and coding.

6.2.3 Build Management

Making sure that you and others can build the system easily.

A good build manager will not only compile and link the source code…

It will also run the tests

making it more difficult to not test after every change

and update the documentation and reports

again, actually requiring the programmer to work harder to let these things get out of sync than to keep them up to date

6.2.4 Version Control

The ability to track changes in the software.

Avoid accidentsresolve conflicting changesExplore ideas, then discard ones that turn out to be undesirable

6.2.5 Configuration Management

How do we cope with importing third-party libraries that are themselves changing and have version depencies among themselves?How do we cope with dependencies of our own software upon the underlying platform?

Page 36: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

6.2.6 Documentation Management

Integrating documentation into the development process,minimizing the “chore”.

Page 37: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Account Setup

Author: Date: Mar 25, 2020 TOC: yes

1 Do you have an active CS Network account?Important: The CS Dept maintains its own network of Windows PCs and Unix machines. These are separate from the general University PCs maintained bythe ITS (the general university computing services).

In this course, you need a CS network account, which is entirely separate from the general University account you get from ITS.

If you had a CS account in the past (if you took other CS courses, you probably did), it should be reactivated. Follow the steps [Confirming Your Account][] tobe sure.

2 If You Have Never Had A CS AccountBrowse to http://www.cs.odu.edu and click on “Account Creation”.

After following the account creation procedure, use the browser to view your ODU email and wait for the authentication message.

After authenticating, you will probably need to finish the steps below on another day.

3 Confirming Your AccountIf/when You Have A CS account…

3.1 The CS Windows NetworkLog in on one of the Windows PCs.

If you are on-campus, the CS Dept has labs in Dragas and E&CS.

If you are off-campus, you can do this via the Virtual PC Lab. Open a browser and go to the CS Dept home page. Look for the link to the “VirtualComputing Lab”. Follow the instructions given there under “Connecting” to open a Remote Desktop Connection to a virtual lab machine.

Page 38: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

If you have a CS account login, but have forgotten your password, go to the CS Dept home page and click on “Password Reset”.

If your account is not working for some other reason, contact the system staff.

3.2 The CS Unix NetworkUsing an ssh client, log in to one of our Linux servers.

If you are able to log in, give the command “pwd”. It should respond “/home/yourLoginName”

If you see anything else (most likely, just “/”), then there was a problem with your account setup. Contact the system staff.

If all looks OK, then give the command “exit” to log out.

4 If You Have Problems4.1 Account Problems: Contacting the CS Systems StaffImportant: the CS Dept.’s computing facilities are separate from the general University facilities run by the ITS. ITS staff at the Technical Support Center inWebb Center cannot, in most cases, help you with account problems on the CS Dept. network.

To contact the CS Dept systems staff, send email to [email protected]. As with any emailed communication, you will get the most satisfactory results if youdescribe your problem clearly and fully.

4.2 Problems with Website RegistrationIf you encounter problems when trying to register with either the CS350 website, it’s probably not something the CS systems staff can help with, because if youhave done the prior steps, we already know you have a working account.

Be aware that my own lists of students enrolled in the course and of newly-issued login names for students who have created accounts is updatedovernight.

If you have enrolled in the course within a day or two, it takes up to a day for ODU to provide that info to us, and then up to a day for my website to pickit up.

If you have just created a CS network account, my website will not know it until the next morning.

Contact the course instructor ([email protected]) if that does not resolve the problem.

Page 39: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What Makes Software Development Difficult?Steven J Zeil

Last modified: Dec 21, 2019

Abstract

Not surprisingly, the title question is of much interest to developers and their managers. There have been quite a few studies devoted to that subject.

One place where identifying complicating factors comes into play is in trying to estimate the cost of a project before it can begin.

A number of different cost models have been proposed.We’ll look at one of them to get a sense of the community consensus on what the factors might be.

1 Opening DiscussionHow do you expect professional software to differ from “academic” software development?

What are some of the factors that make some software development projects especially difficult?

2 Lessons from a Cost ModelOne of the best known software development cost models is

COCOMO (COnstructive COst MOdel) by B. Boehm, 1981

The Intermediate Cocomo formula estimates effort ( ) in person-months:

KLoC stands for “Kilo (thousands) of Lines of Code”, and represents an estimate of how large a propsoed project is going to be.

Coming up with that estimate is a separate and non-trivial taskThe rest of the effort formula is an attempt to figure out how hard it will be to develop that many lines of code.

E

E = (KLoC ⋅ EAFai )bi

Page 40: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The constants and describe the characteristics of the development team.

These are obtained by fitting the model to the costs observed in past projects developed by the same team.

2.1 ExampleSuppose that in previous projects of various sizes, our company’s performance had fitted to , .

If we are looking at doing a 10 KLOC project that is very similar to past projects, the estimated effort would be

(The EAF will be 1.0 if this project is very similar to past ones.)

If we are looking at doing a 20 KLOC project that is very similar to past projects, the estimated effort would be

2.2 EAFThe most interesting part of the COCOMO formula is the EAF, a multiplier computed from a checklist of project attributes.

Each attribute describes some characteristic that affects how hard it is to develop software.The team managers assign each attribute an estimated rating ranging from “Very Low” to “Extra High”

This yields a multiplier value for that characteristic,1.0 is “average”values > 1.0 mean that more effort is requiredvalues < 1.0 mean that less effort is required

2.2.1 Cost factors

Ratings

ai bi

a = 3.0 b = 1.12

E = (KLoC ⋅ EAFai )bi

= 3.0 ⋅ ⋅ 1.0101.12

= 40person-months

E = (KLoC ⋅ EAFai )bi

= 3.0 ⋅ ⋅ 1.0201.12

= 86person-months

Page 41: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Cost Drivers Very Low Low Nominal High Very High Extra HighRatings

Cost Drivers Very Low Low Nominal High Very High Extra HighProduct attributesRequired software reliability 0.75 0.88 1.00 1.15 1.40Size of application database 0.94 1.00 1.08 1.16Complexity of the product 0.70 0.85 1.00 1.15 1.30 1.65Hardware attributesRun-time performance constraints 1.00 1.11 1.30 1.66Memory constraints 1.00 1.06 1.21 1.56Volatility of the target environment 0.87 1.00 1.15 1.30Required turnabout time 0.87 1.00 1.07 1.15Personnel attributesAnalyst capability 1.46 1.19 1.00 0.86 0.71Applications experience 1.29 1.13 1.00 0.91 0.82Software engineer capability 1.42 1.17 1.00 0.86 0.70Target environment experience 1.21 1.10 1.00 0.90Programming language experience 1.14 1.07 1.00 0.95Project attributesApplication of software engineering methods 1.24 1.10 1.00 0.91 0.82Use of software tools 1.24 1.10 1.00 0.91 0.83Required development schedule 1.23 1.08 1.00 1.04 1.10

2.3 ExampleSuppose that in previous projects of various sizes, our company’s performance had fitted to , .

If we are looking at doing a 10 KLOC project that is very similar to past projects, the estimated effort would be

But suppose that we have decided to write this project in a programming language that is new to our team, and for which our preferred debugging tools areunavailable.

a = 3.0 b = 1.12

E = (KLoC ⋅ EAFai )bi

= 3.0 ⋅ ⋅ 1.0101.12

= 40 person-months

Page 42: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The EAF table says

RatingsCost Drivers Very Low Low Nominal High Very High Extra High

Programming language experience 1.14 1.07 1.00 0.95Use of software tools 1.24 1.10 1.00 0.91 0.83

So we might guess that our EAF = 1.254, so those two factors add an additional 25% to the effort estimate:

2.4 Trends

RatingsCost Drivers Very Low Low Nominal High Very High Extra High

Product attributesRequired software reliability 0.75 0.88 1.00 1.15 1.40Size of application database 0.94 1.00 1.08 1.16Complexity of the product 0.70 0.85 1.00 1.15 1.30 1.65Hardware attributesRun-time performance constraints 1.00 1.11 1.30 1.66Memory constraints 1.00 1.06 1.21 1.56Volatility of the target environment 0.87 1.00 1.15 1.30Required turnabout time 0.87 1.00 1.07 1.15Personnel attributesAnalyst capability 1.46 1.19 1.00 0.86 0.71Applications experience 1.29 1.13 1.00 0.91 0.82Software engineer capability 1.42 1.17 1.00 0.86 0.70Target environment experience 1.21 1.10 1.00 0.90Programming language experience 1.14 1.07 1.00 0.95Project attributesApplication of software engineering methods 1.24 1.10 1.00 0.91 0.82Use of software tools 1.24 1.10 1.00 0.91 0.83

= 1.14 ∗ 1.10

E = (KLoC ⋅ EAFai )bi

= 3.0 ⋅ ⋅ 1.25101.12

= 50 person-months

Page 43: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

RatingsCost Drivers Very Low Low Nominal High Very High Extra High

Required development schedule 1.23 1.08 1.00 1.04 1.10

Some of the trends are obvious.

As required reliability and product complexity increase, so does the effort requiredAs the team’s level of experience with the application area, the target environment, and the programming language increase, the expected effortgoes down.

Some of the trends are not monotonic.

As the required development schedule becomes more rigorous, the effort initially decreases (concrete deadlines may motivate performance) andthen increases (stress and the need for compromises to meet deadlines).

3 Things to think aboutConsider a project with the following characteristics:

Large development teams withhigh turnovervastly different levels of experience / ability

Minimal opportunity for face-to-face communication

What do you think the EAC would be for this project?

Can you think of a situation where these project characteristics are common? +

Page 44: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Consider a typical open source project on SourceForge or similar sites. They can be staffed largely by volunteers, working remotely. The developers may noteven live and work in the same timezone, so face-to-face meetings are unlikely and most communication will be asynchronous (e.g., e-mail).

The participants may range from seasoned veterans to near-novices.

By conventional thinking, it’s a wonder that such projects ever succeed!

Page 45: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Software Development Process ModelsSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Software Development Process Models

1.1 Common Activities2 Major Software Development Models3 The Waterfall Model

3.1 Verification & Validation3.2 Testing throughout the Waterfall3.3 Advantages of Waterfall3.4 Disadvantages of Waterfall

4 Iterative/Incremental Development4.1 Advantages4.2 Disadvantages

5 The Spiral Model5.1 Advantages of Spiral Model5.2 Disadvantages of Spiral Model

6 Rational Unified Process6.1 Unified Model Phases6.2 Unified Model Phases Continued6.3 Key Concepts of the RUP6.4 Advantages of RUP6.5 Disadvantages of RUP

7 Agile Methods

Abstract

Each development organization has its own working process that it evolves for how it gets software development done. In this lesson, we look at the constituentsteps that make up typical instances of these processes, and will survey some of the more common arrangments of those steps into a software developmentprocess model:

the Waterfall ModelIterative and Incremental ModelsThe Spiral ModelThe Rational Unified Process

Page 46: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Agile models

1 Software Development Process ModelsAbstract

Each development organization has its own working process that it evolves for how it gets software development done.

Although that might sound chaotic, in practice there is pretty broad consensus on what the constituent steps are that make up the entire process. So it becomes amatter of arranging those steps, of tweaking the details, and especially of settling on the relative emphasis and level of detail in these steps.

The arrangements that companies arrive at are seldom entirely innovative. Instead, they fall into a few standard patterns, which we will survey in this lesson.

A software development process model (SDPM), a.k.a., a software life-cycle model, is the process by which an organization develops software.

Projects typically broken into phasesThere are varying criteria for entering or exiting each phase

1.1 Common ActivitiesAlthough there are many models (in theory, one per development team), there is pretty broad agreement on what needs to go on during this process:

1. Recognition of problem / need / opportunity2. Feasibility study3. Analysis of requirements4. Design of system5. Implementation6. Testing7. Deployment8. Maintenance

Different SDPMs will divide these activities among phases in different ways.

Let’s talk about a few of these in more detail.

1.1.1 Analysis of Requirements

Examine existing system.

How does it work?

Page 47: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What are its shortcomings?

Propose a new system

Enumerate precisely what the new system will do

“System” here is used in its generic sense: a collection of people, organizations, machines, and procedures for getting things done. There’s almost always anexisting system, even if it is totally un-automated.

If you are a follower of Object-Oriented (OO) approaches, you have a deep conviction that studying and, ultimately, simulating an existing system is afundamental principle of software development. OO developers never ask the question “Is it possible to build a system that does X?”. That’s because the existingsystem serves as an existence proof — they’re already doing X, so we start by understanding and then simulating what they are doing now.

Common Documents from Requirements Analysis

Feasibility reportSoftware Requirements Specification (SRS)

Detailed statement of problemFunctional requirementsConstraints on the system

We’ll look at requirements in more detail in a later section.

1.1.2 Design

“Design” means deriving

a solution which satisfies the software requirements.

Commonly recognized subproblems include

architectural design,

the collection of decisions that need to be common to all components.

Examples of architectural design decisions would be

Will the system run on a single machine or be distributed over multiple CPUs?Will outputs be stored in a file or in a database?How will run-{}time errors be handled?

high-level design,

Page 48: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

dividing the system into components, and

low-level design

choosing the data structures and algorithms for a single component.

A possible breakdown of design activities

You are probably pretty familiar already with procedures for doing high-level and low-level design. Architectural design, on the other hand, is something that isseldom worth worrying about in the scale of projects addressed within an academic semester.

The breakdown shown in this picture is probably more elaborate than you would have attempted, though the component ideas should, considered separately, beclear enough.

The diagram here suggests a fairly document-heavy process typical of Waterfall, our first process model.

1.1.3 Maintenance

Maintenance is another practice that seldom arises in academic projects. Normally, when you do an assignment for a course, you’re completely done with at theend of the semester. Keeping it working, adding new functionality, etc., is not a concern.

But you’ve certainly seen how operating systems, application programs, games, and many other software products are subject to an ongoing process of bugfixes, enhancements, and new releases.

Maintenance can have a number of forms:

Corrective

Page 49: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

fixing problems

Adaptivechanges in environment

Perfectiveadding featuresimproving performance

Preventativerefactoring to improve maintainability

Refactoring is a change made that preserves the current behavior of the system.

2 Major Software Development ModelsThe Waterfall ModelIterative and Incremental ModelsThe Spiral ModelThe Rational Unified ProcessAgile Models

3 The Waterfall Model

The best known process model

dates from 1970’sthough widely derided, it remains widely used

and its terminology forms the basis for almost all discussions of other SDPMs

Defining characteristic: movement from phase to phase is always forward (downhill),irreversible

Milestones are set at each phase transitionschedule deadlinesrequired reportsrequired approval to move on

The waterfall model gets its name from the fact that the first diagrams of this process illustrated it as a series of terraces over which a stream flowed, cascadingdown from one level to another. The point of this portrayal was that water always flows downhill — it can’t reverse itself. Similarly, the defining characteristicof the waterfall model is the irreversible forward progress from phase to phase.

Page 50: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Waterfall is often criticized as inflexible, in large part because of that irreversible forward motion. Many organizations, in practice, will do a kind of “waterfallwith appeals”, allowing developers to revisit and revise decisions and documents from earlier phases after jumping through a number of deliberately restrictivehoops.

3.1 Verification & ValidationMost of the activities in Waterfall are familiar, with the possible exception of requirements analysis, which we will be looking at in more detail in a later lesson.

For now, I want to look at Verification and Validation (V&V).

Verification & Validation: assuring that a software system meets the users’ needs.

The principle objectives are:

The discovery of defects in a systemThe assessment of whether or not the system is usable in an operational situation.

3.1.1 What’s the Difference?

Verification:

“Are we building the product right” (Boehm)The software should conform to its (most recent) specification

Validation:

“Are we building the right product”The software should do what the user really requires

Verification is essentially looking for mistakes in our most recent bit of work by comparing what we have now to the most recent “official” document definingour system.

Validation is a return to first principles, comparing what we have now to what we (or our customers) originally wanted.

You might think that, in a process divided into steps, if we do each step “correctly”, then the entire sequence must be “correct”. In practice, though, theaccumulation of small errors can lead to massive alterations over time. (That’s not just a matter for programmers.)

Most V&V activities mix verification and validation together to different degrees.

Testing

Page 51: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Testing is the act of executing a program with selected data to uncover bugs.As opposed to debugging, which is the process of finding the faulty code responsible for failed tests.

Testing is the most common, but not the only form of V&V

Industry figures of 1-3 faults per 100 statements are quite common.

Is testing verification or validation? A great deal depends on how we decide whether the test output is correct. If we do this by viewing the data ourselves andlooking for things that jump out to our eyes as “wrong”, then we are doing mainly validation. On the other hand, if part of our design process was to set up a setof tests with files of their expected outputs, and we are simply comparing the actual output files to the expected output files, then we are doing moreverification.

3.2 Testing throughout the Waterfall

3.2.1 Testing stages

Unit Test: Tests of individual subroutines and modules,

usually conducted by the programmer.

Integration Test: Tests of “subtrees” of the total project hierarchy chart (groups of subroutines calling each other).generally a team responsibility.

System Test: Test of the entire system,supervised by team leaders or by V&V specialists.Many companies have independent teams for this purpose.

Regression Test: Unit/Integration/System tests that are repeated after a change has been made to the code.Acceptance Test: A test conducted by the customers or their representatives to decide whether to purchase/accept a developed system.

3.2.2 Not just in one phase

Although the waterfall model shows V&V as a separate phase near the end, we know that some forms of V&V occur much earlier.

Requirements are validated in consultation with the customers.Unit testing occurs during Implementation, etc.

So this phase of the waterfall model really describes system and acceptance testing.

Page 52: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A Still-broader View

Even the “V&V V” does not capture the full context of V&V:

Requirements must be validatedDesigns may be validated & verifiedMaintenance changes are tested

3.3 Advantages of WaterfallLinear structure is easy to understandDevelopment progress is easily estimated and explicitly documentedWidely knownScales well

3.4 Disadvantages of WaterfallInflexible: corrections limited to current phaseIn some projects, requirements are not known or understood early in the life-cycleWorking version of system is only available near the endOften becomes a documentation mill

Page 53: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4 Iterative/Incremental Development

A variety of related approachesa counter-reaction to what many believe to be an overly rigid, management-focused,waterfall model

emphasize quick cycles of development, usually with earlier and more user-orientedvalidationRequirements specification, design and implementation are interleaved.Each version adds a small amount of additional functionality.

As a counter-reaction to what many believe to be an overly rigid waterfall model, there are a varietyof incremental approaches that emphasize quick cycles of development, usually with earlier and more user-oriented validation.

There is a greater emphasis on producing intermediate versions, each adding a small amount of additional functionality. Some of these are releases, eitherexternal (released outside the team) or internal (seen only by the team), which may have been planned earlier.

What’s the difference between iterative and incremental?

“Iterative” means that we can re-visit decisions, design, and code produced in earlier iterative steps.

“Incremental” means that each iteration produces just a small unit of additional functional behavior. We don’t try to build major subsystems of the projectin a single pass.

This often requires a more “vertical” view in which we implement a bit of high level control code and pieces of related low-level code.

As opposed to the “horizontal” approach of working “bottom up” and implementing the low-level ADTS, then the code that calls, upon them, then…, ending with the top-level interface ot the whole program.

Or the “horizontal” approach of working “top down” and implementing the most abstract code (the GUI or command-line interfaces), thenfunctions that they call, then the … ending with the lowest-level ADTS that don’t call on anything else.

Iterative versus Incremental Models

Iterative – we do some set of process steps repeatedly.

To use a programming analogy, this is iterative:

while (!done) { ⋮

Page 54: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

}

Incremental – we accumulate value in small steps.

To use a programming analogy, this is incremental:

total += x;

Incremental development is almost always iterative, but you can be iterative without being incremental.

Variations

Some projects employ throw-away prototyping, versions whose code is only used to demonstrate and evaluate possibilities.

This can lead to insight into poorly understood requirements.

Evolutionary prototyping keeps the prototypes, gradually evolving them into the final deliverable

Some waterfall projects may employ incremental schemes for parts of large systems (e.g., the user interface).

4.1 AdvantagesAbility to explore poorly understood requirementsFlexibilityWorking implementation is available early.

4.2 DisadvantagesPoor process visibility (e.g., are we on schedule?),

Continual small drifts from the main architecture leading to poorly structured systems.

Dead-ends (the local optimization problem)

5 The Spiral Model

Page 55: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1986, Boehm

An iterative approach with a focus on risk management

Each iteration builds on the earlier ones

risk: an uncertain outcome with a potential for loss

Examples:

team inexperienceinability to meet scheduleuncertainty in requirements

Spiral Phases

1. Determine objectives, alternatives and constraints:Define requirementsAlternatives (including, e.g., 3rd-party code) identifiedConstraints defined

2. Identify and resolve risks, evaluate alternatives:Evaluate identified alternativesIdentify risksResolve risksProduce prototype

3. Develop and testAnalyze performance of prototypeCreate & review design, code, test

4. Plan next iterationOften includes customer evaluation of prototype or current project iteration

Page 56: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

5.1 Advantages of Spiral ModelFlexible – emphasis on alleviating risks as they are identifiedConsiderable opportunity for validationScales wellGood process visibilityWorking releases/prototypes produced early

5.2 Disadvantages of Spiral ModelCan be costly (slow?)Risk analysis is a specialized skill, but critical to project success

6 Rational Unified Process1997, Jacobsen, Booch, and Rumbaugh,

Best Practices

Develop iterativelyManage requirementsUse componentsModel visuallyVerify qualityControl changes

These three were already some of the biggest names in OOA&D before they decided to collaborate on a unified version of their previously distinctiveapproaches.

Their collaboration coincided with their being hired by Rational Corp., a major vendor of software development tools. Hence the “Rational” in RUP refers tothe name of the company. It’s not bragging. They aren’t saying that this is a uniquely intellectual approach or that Waterfall, Spiral, et. al., are “irrational”.

6.1 Unified Model Phases

Page 57: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Inception: initial concept

Pitching the project conceptUsually informal, low details.“Perhaps we should build a … ”

Elaboration: exploring requirements

Adding detail to our understanding of what the system should do.Produces

Domain modelAnalysis modelRequirements documentRelease plan

6.2 Unified Model Phases ContinuedConstruction: building the software

Design & implementation

Transition: final packaging

Activities that can’t be done incrementally during construction, e.g.,performance tuninguser training

Releases

One task during Elaboration is to plan releases:

Major phases are divided into increments, each of which ends with a release.

A release is some kind of product that implements some part of the required functionality

Page 58: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Its existence and/or acceptance by management shows that we are ready to move on.

The release plan records decisions about

How many releases there will beWhat functionality will be added with each releaseWhen the releases will be madeWhich releases are internal (i.e., only the development team sees them) and which are external

The term “increments” gets used a lot in different models. Sometimes it refers, as it does here, to the time period during which the next release of the software isdeveloped. In other cases it refers to the next version of the software. In other cases it refers to the software release itself.

6.3 Key Concepts of the RUP

6.3.1 Common Workflows

Although waterfall and other SDPMs treat analysis, design, etc., as one-timephasesCareful study shows that developers do analysis, design, etc., activitiescontinuously.

Analysis: what do we need the (currently considered part of the)system to do?

Design: how do we get it to do that?

Implementation: write out that series of design decisions in anappropriate notation (e.g., code, diagrams, requirements statements)Validation: Is our implementation correct?

For example, deep in the implementation phase of a Waterfall project, aprogrammer is assigned a function to implement.

That programmer will

think carefully about what the function is supposed to do (analysis)choose an algorithm that will accomplish that (design)code the function (implementation)unit-test that function (validation).

Page 59: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

But we aren’t in the analysis, design, or validation phases.

The diagram on the right is supposed to illustrate that, although the percentage of time devoted to the activities of analysis, design, implementation, andvalidation, none of those activites ever entirely go away and are, once and for all, done.

A process model may still use some of these same terms as the name for major phases, but that’s really a different sense of the terms. For example, the “Design”phase of the Waterfall is when the language in which we “implement” is the collection of notations and diagrams that we use for system design. But we stillanalyze, design, implement, and validate our Design decisions.

ADIV

In the RUP, all progress is made as continual ADIV cycles

ADIV: Analysis, Design, Implementation, Validation

6.3.2 An Evolution of Models

RUP supports development via a series of models.

The most important of these are

Domain Model

A model of the application domain as it currently exists, before we began our new development project.Ensures that the development team understands the world that the system will work in.

Analysis Model

A model of how the world will interact with the software system that we envision.Expresses what the system will do when it is working.

Page 60: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Design Model

Describes how we can get the system to do the things the analysis model says it should do.

Models Evolved

RUP embraces the

Object-Oriented philosophy

Every program is a simulationThe quality of a program’s design is proportional to how faithfully the objects and interactions in the program reflect those in the real world

Domain, analysis, and design models all focus on how classes of objects interact with one another

Most of the classes in the design are presumed to have already been described as part of the analysis model,

Most of the classes in the analysis model are presumed to have already been described as part of the domain model,

6.4 Advantages of RUPProcess details are expressed in general terms, allowing local customizationHeavy emphasis on documentation (UML)Can embrace incremental releasesEvolutionary approach can lead to clean implementations

6.5 Disadvantages of RUPProcess details are expressed in general terms, providing minimal guidance and requiring local customizationComplexHeavy documentation can be expensive

7 Agile MethodsA modern variant of incremental development.

Page 61: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Agile development is

A reaction against heavily-managed, documentation-heavy processesA social movement within the software development profession

Introduced in the Agile Manifesto (2001)

Emphasis Areas

Emphasis is on

Iterative & incremental developmentFrequent communication with customer representatives

Work is organized via “user stories”Short “time-boxed” development cyclesFocus on quality as a matter of professional prideAdoption of professional best-practices

We’ll look at Agile in more detail later in the semester, after we have learned more about these “best practices” that lie at the heart of the process.

Page 62: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Lab: Secure Shell KeysSteven J Zeil

Last modified: Mar 25, 2020

Contents:1 ssh Isn’t Just for Terminal Sessions2 Replacing Passwords with ssh Keys

2.1 Generate a Key Pair2.2 Try It Out2.3 Key Agents2.4 Creating Special-Purpose Key Pairs2.5 Playing with Fire: Password-Free Key Pairs

This is a self-assessment activity to give you practice in working with the git version control system. Feel free to share your problems, experiences, andchoices in the Forum.

1 ssh Isn’t Just for Terminal SessionsYou should already be familiar with ssh even if you are used to invoking it through PuTTY.

In this lab, you will be working with ssh from a command line. You will be working with

a server machine, which will be one of the CS Dept Linux servers. I will assume in the rest of this document that you are using atria.cs.odu.edu asyour server.

a client machine, at which you can issue ssh commands. This will need to be a different machine from the server.

Ideally, use a PC of your own.

If your PC runs Linux or OS/X, you should be fine.If your PC runs runs Windows 10, good options are Bash on Windows. or the OpenSSH command-line tool in Powershell. (You may need tomake some changes to the paths referenced in these commands if you are working in Powershell.)

Other good options for Windows 10 or for older versions of Windows are CygWin or setting up a Linux virtual machine.

Page 63: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

You can use two different CS Linux servers as your client and server (e.g., atria.cs.odu.edu and sirius.cs.odu.edu) but it’s not ideal. Somemistakes that you might make will be disguised by the fact that you are already logged in to the network via the client machine, so it will be hard totell if your commands are working because you did the lab correctly or because you are already logged in.

Let’s start with just the basics of using ssh from the command line.

1. Try opening a remote session on your server machine by issuing the following command on your client machine:

ssh -l yourCSLoginName atria.cs.odu.edu

You can omit the “-l yourCSLoginName” if your current terminal session is under a user name identical to your CS Dept login name. You can alsocombine it with the machine name, separated by an “@”:

ssh [email protected]

This opens up what should be a familiar text-mode command session on the remote machine. Issue a few commands to verify that everything is familiar,and then log out of the remote machine.

2. Now give the same command, but append a command string to the end:

ssh -l yourCSLoginName atria.cs.odu.edu ls -l

ssh is useful for issuing all sorts of commands to a remote machine. The “default” is to issue the command to open a login shell, but you can issue anycommand you want.

ssh has other tricks to offer as well.

ssh servers also, by default, provide file copying services via scp and sftp..

The ssh protocol can act as a “tunnel” for other common network protocols (e.g., email). This includes protocols that normally are limited to localnetwork connections or that, for other reasons, have trouble getting through firewalls and routers. For example, all of the techniques covered in CS252 forconnecting via X Windows have actually relied upon an ssh tunnel to carry the X or NX protocol messages between the two machines.

We’ll be making heavy use of both of these features of ssh in the coming semester. However, these will call for a more sophisticated approach to identifyingourselves than explicitly typing in our login names and passwords for every connection to a network service.

2 Replacing Passwords with ssh Keysssh keys provide a way of identifying yourself that is generally more secure than simple passwords. Based on one-way cryptography, an ssh key has two parts: apublic key and a private key. You can distribute the public key to a variety of server systems that you like to log in to. You keep the private key on clientmachines that you log in from. Often these client machines are ones you have a certain amount of physical control over — a home computer or a laptop that you

Page 64: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

own. That physical security is coupled with a lengthy passphrase needed to activate the private key. Once activated, the private key can be kept active through awork session, allowing you to repeatedly log in to clients that have your public key.

It’s important to keep this straight: * The public key goes onto the remote server that you are connecting to. * The private key stays on your (local)client that you are connecting from.

2.1 Generate a Key PairThe ssh-keygen program is most commonly used to generate public/private key pairs.

Most Linux systems will have this already installed.

On a Windows CygWin system, you can get it as part of the openssh package.

Another possibility is Pageant, part of the PuTTY ssh suite for Windows.

Also, you can generate keys from within Eclipse (Window Preferences General Network Connections SSH2 Key Management,but the key length is limited to 1024 bits, which is considered a bit low these days.

1. To generate a key pair, give the commands:

mkdir ~/.ssh # if you don't already have this directory chmod 700 ~/.ssh ssh-keygen -b 2048 -t rsa

You can do this step on your client machine or on the remote Linux server.

You can change the name of the generated files if you like. (I keep different key pairs for different client machines and name them accordingly, e.g.,“officePC”, “homePC”, etc.). Do keep it in your ~/.ssh directory, however.

You will be prompted for a passphrase. This is used to protect your private key in case someone gains access to the machine/account where you have itstored. Do choose one. Even though the command prompt says it’s optional, you don’t want to have an unprotected private key around. Most people usemuch longer passphrases than a typical password, but generally place less emphasis on odd character substitutions that make the phrase harder to type.

2. Now look in your ~/.ssh directory. You should see your new keys. One file has the extension “.pub”. that’s the public part of the key.

3. You can do a quick test of your key pair by giving the command

⇒ ⇒ ⇒ ⇒ ⇒

Page 65: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

This is, by the way, an excellent way to check tosee if a pair of files really do belong together as apublic/private key pair, or to check if you haveforgotten your passphrase.

ssh-keygen -y -f path/to/your/private-key

This command will prompt you for your passphrase and, if you are successful in providing it, willthen print the corresponding public key.

Compare the output of that to

cat path/to/your/public-key

They should match except for the little “usr@machine” comment at the end indicating the machine on which you created the key.

Remember, the idea is that you want the public key to be on the remote server and the private key on your local client.

Since you have just created both keys on one machine, one of them is currently out of place.

4. If you created your key pair on your client machine, transfer the public key into your ~/.ssh directory on the remote server. (If you don’t have a ~/.sshdirectory there, create one. Give is the same permissions as shown in step 1, above.)

If, on the other hand, you created your key pair on the remote server, transfer the private key to a convenient directory on your local client, and delete theoriginal private key from the remote server.

2.2 Try It OutAt this point, you should have

A copy of the private key on the local client.A copy of the public key on the remote server.

But just having the public key on the remote server isn’t enough. We have to authorize that key before it will do anything for us.

1. Let’s authorize this key as one that you can use to log in to your CS Linux account.

On Linux servers, you do this by adding the public key to ~/.ssh/authorized_keys. authorized_keys is simply a text file that contains a list of publickeys.

There’s at least three ways to do this.

You can simply attach it to the end of the authorized_keys file:

Page 66: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

cd ~/.ssh touch authorized_keys cp -a authorized_keys authorized_keys.bak cat path/to/your/publicKeyFile >> authorized_keys

This works the first time you install a key. But if you need to replace or modify a key, it’s not as useful, because you would wind up with multiplecopies of the same key in your authorized_keys file, leading to unpredictable results.

Alternatively, log in to the server, open ~/.ssh/authorized_keys in your favorite text editor and add the public key to the end. (This is also howyou can clean up this file later if you want to remove a key, either because the key doesn’t work properly or to clean up after this assignment isdone and graded.)

If you are replacing a key, be sure to delete the old entry for that key. If you have entries in there for keys you aren’t using, remove those aswell.

You might read on the Internet about a command ssh-copy-id that combines the file transfer of a public key from a client and the authorizationinto a single step.

Since we are going to be modifying the authorized keys shortly, however, I don’t recommend this. People who rely on this command often wind upwith messy authorized_keys files that are hard to work with.

2. Now, back on your client machine, try connecting to the server:

ssh -i path/to/your/PrivateKey -o "IdentitiesOnly=yes" [email protected]

You should be prompted for the passphrase for your new key.

Troubleshooting

If you run into problems with the final step or with the ones that follow, …

1. Review your steps. Make sure that you have the correct files on the correct machines.

Remember, the public key goes on the remote server inside the authorized_keys file.

The private key goes on your local client machine.

That means that when you are giving a path to your private key in an ssh command, it must be a path on your local machine.

2. Check your permissions on the server very carefully. You should have the equivalent of:

Page 67: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What is an “agent”? An agent is a program that runs, usuallyin the background, and performs some action on your behalfwhen the right conditions present themselves, without requiringyour attention or intervention.

chmod 711 ~

chmod 700 ~/.ssh

chmod 600 ~/.ssh/authorized_keys

3. You may also need to check the permissions on your private key on your local client. Some versions of ssh will refuse to use a private keythat is readable by anyone other than you (the owner of the file).

In particular, if you get a message complaining that your private key permissions are too open, change the permissions on that key!

chmod 600 path-to-your-private-key

If you are using Bash/Ubuntu on Windows, you may find that chmod commands like the one above are ignored. (Do an “ls -l …” tocheck.)

You may be able to make chmod work by using an editor:

sudo nano /etc/wsl.conf

and adding the lines

[automount]

options="metadata"

Then close all open bash instances, restart bash, and see if your chmod commands now work.

2.3 Key AgentsWait, did we just make your life harder?

Now, you may wonder what good that was. Every time you try to log in to a CS Linux machine, you will be prompted for that passphrase, which is probablymuch longer than your old password.

But usually, we don’t activate the private key for a one-shot login. Instead, we run a keyagent on our client machine. We tell it to activate our private key (giving it the passphraseto prove that we are its owner). It then watches for subsequent ssh connection attempts andoffers up the activated private key.

Page 68: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Take note that the ssh-agent command is inside backticks, not apostrophes.

An example of a typical agent is the process that runsperiodically when you have your email program open, thatchecks every few minutes to see if new mail has arrived.

What is as “ssh key agent”? This is an agent that watches forincoming attempts by a remote server to validate an ssh key andautomatically confirms that you have already unlocked that keywith the appropriate passphrase.

1. On your client machine:

eval `ssh-agent` ssh-add ~/.ssh/yourPrivateKeyFilename

This launches a new key agent and tells it to watch for incomingrequests to validate that private key.

2. Then try giving the following commands from your client

ssh [email protected] date ssh [email protected] pwd ssh [email protected] ls ssh -A [email protected]

All of these should work with your being prompted at most once for your passphrase. The last one leaves you logged in to atria. From that session onatria, try logging in to sirius:

ssh sirius.cs.odu.edu

Again, you should find that you are able to do this without being prompted for your password or passphrase. The -A option in the earlier ssh commandcaused your agent’s credentials to be forwarded into your session on atria.

If you like this, you should look into the package keychain, which is a way to set up agents and activate your keys upon logging in to your client. If you don’tcare for it, restore your authorized_keys file in your CS account to its previous state (the .bak file). But keep those keys. We’ll use them later.

2.4 Creating Special-Purpose Key PairsSuppose that you wanted to allow someone else to try out a program that you had written and that is sitting somewhere in your account area. Let’s also supposethat you don’t want to make this program available to the entire world. For example, perhaps you are working on a programming assignment in one of mycourses and you want me to take a look at your running program.

Page 69: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

You could, of course, tell me your login name and password, but that would be a bad idea unless you really, really trust me. (And why should you?)

Based on what we have just seen, you could create an ssh key pair, add the public key to your authorized_keys file, give me the private key and itspassphrase. Then, after I had tried your program out, you could simply remove that key from ~/.ssh/authorized_keys to lock me back out.

But that’s still way too trusting of you. During the time I had access to your program, I would have access to everything in your account. I would, evenusing the ssh keys, be logged in as you.

But we can actually adapt that second approach by limiting the key pair to running only a specific command or program when anyone uses it to log in.

1. On the remote server, edit the public key that you created in the earlier steps.

The key is typically written as a single long line ending in _yourLoginName@machineName_, reflecting where you created the key. To the front of thatline, add

command="/usr/bin/env",no-port-forwarding

and a blank space, right in front of the “ssh-rsa”.

(If you aren’t familiar with the env command in Linux, run it to see what it does.)

2. Add that edited public key to your authorized keys list on the server as you did earlier. (Remove the old copy of that key.)

3. You should still have a key agent running on your client. If not, restart it and add your private key.

Now try logging in via that key by giving the following commands on the client:

ssh [email protected] ssh [email protected] pwd

Notice that, whether you give a specific command for ssh to execute on the remote server or omit it, trying for a normal login session, what actuallyhappens is that you are logged in to your account, the env command is run, and then you are logged out.

So, to return to our earlier example, if you were working on a programming assignment in one of my courses and you want me to take a look at your runningprogram, you could create a special-purpose key pair to run that program (and do nothing else), and then give me the private key and passphrase, knowing that Iwould be limited to using your account for that single purpose.

2.5 Playing with Fire: Password-Free Key PairsNow we are going to do something a bit dangerous.

1. Shut down the key agent on your client machine with the command

Page 70: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

ssh-agent -k

2. Create a new key pair, giving them a different name from the ones you set up earlier.

This time, however, when prompted for a pass phrase, just hit Enter to create a key pair without a pass phrase.

3. Test your keys via the commands

ssh-keygen -y -fpath/to/your/privateKey cat path/to/your/publicKey

Again, the printed public keys should match except for the trailing comment. This time, however, you should not be prompted for a passphrase.

4. If you created these keys on the remote server, transfer the private key to your local client machine and delete the original.

If you created these keys on your local client, transfer the public key to your ~/.ssh/ directory on the remote server.

5. Now, adding that key to your authorized key list would be risky, because anyone who got a copy of the private key would be able to log into your accountusing no passphrase at all.

So, to keep this safe, immediately edit that public key. This time add

command="pwd",no-port-forwarding,no-agent-forwarding

to the beginning of the public key.

6. Add that edited public key to your authorized key list on the server.

7. On the client, give the command

ssh -i path/To/Your/New/Private/Key [email protected]

You should see that the command is executed without your being prompted for a password or pass phrase.

If you are still prompted for a password, there may be remnants of your ssh-agent interfering. Try

ssh -o IdentitiesOnly=yes -F /dev/null -i path/To/Your/New/Private/Key [email protected]

When you have succeeded in completing these steps, remove the keys you have added to your ~/.ssh/authorized_keys file on the server.

Page 71: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Team OrganizationSteven J Zeil:

Last modified: Dec 21, 2019

Contents:1 Issues

1.1 Communications2 General Organizations

2.1 Hierarchical Team Organization2.2 Matrix Organization

3 Software Team Organizations3.1 Chief Programmer Teams3.2 SWAT Teams3.3 Agile Teams3.4 Distributed Teams

Abstract

Development teams are organized to

promote communication among the team members and between th team and interested external partiesmatch required skills against needs of the projectenhance overall productivity of the team

In this lesson, we look at some of these issues and at some common organizations that have been considered to deal with these.

1 IssuesMajor issues in organizing a development team are

Communication

maximize communication within the team

establish responsive communication points with stakeholders

Page 72: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Staffing

does the team contain all the skill sets reuqired to complete the work?

Productivity

are we making effective use of our team members’ skills?

1.1 CommunicationsThere are two key aspects here

internal communications within the teamexternal communications with interested parties

1.1.1 Internal Communications

Brook’s law is well-known truism of software development:

"Adding manpower to a late software project makes it later. – Fred Brooks, _The Mythical Man-Month, 1975

Why?

Brooks argues that

Complex projects cannot be decomposed into subprojects that can be solved independently without communication.

He suggests that partly, this is an attribute of the problem being solved.

Essential versus accidental complexity

He suggests that sometimes we add complexity by our choices of process or design, but that some problems are just plain complicated. As a consequence,he suggests that there is an

irreducible number of errors

that we will always commit along the way, and that this is independent of the number of people we have working.

But he also argues that

Page 73: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

More personnel implies more communications paths

staff have potential communications paths.

Reducing Internal Communications Costs

Our options are limited

Keep teams small, orStructure the teams in ways that facilitate the most critical communications paths

1.1.2 External Communications

We can divide this into

communications with the development team’s own managementcommunications with the eventual users of the software

Historically, the former has been emphasized

visibility of the process is a major factor in Waterfall & Spiral

Over time, more and more emphasis has shifted to communications with the users.

Users, Customers, and Stakeholders

“Users” is an incredibly vague, catch-all term that serves to hide as much as it reveals.

Avoid it when possible.

Customers are the people who have the authority to accept or reject the system, to pay for it or not.

“Pay” is not necessarily a simple monetary transaction.(e.g., internal projects)

Stakeholders are the people with an interest in the structure and behavior of the system.

Example:

A company’s upper-level management approves budget to develop a system. They are the customers.

nn(n−1)

2

Page 74: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The output of the system is a series of reports used on a monthly basis by the company’s middle and low-level managers. They are stakeholders, becausethey have an interest in the content and format of those reports.

Much of the input of the system will be supplied by the company’s clerical staff, sales people, and technicians. They are also stakeholders, because thesystem will directly impact their daily jobs.

We look to customers for general guidelines on what will make the valuable and acceptable to them.

We look to stakeholders for much of the insight into how the system needs to work.

2 General OrganizationsThere are a few “obvious” ways to organize developers into a team.

One might be the basic democracy (or anarchy) of everyone working as peers.

You probably don’t need very large teams before this gets unwieldy.

2.1 Hierarchical Team OrganizationOne team per major subsystemTeams report to managersManagers report to one or more levels of higher managers

Dangers of Hierarchical Teams

Distance between teams (where real work is done) and higher mgmt may hide problems.

I like van Vliet’s example:

"The following scenario is not entirely fictitious:

bottom: we have severe troubles in implementing module X;

level 1: there are some problems with module X;

level 2: progress is steady, I do not foresee any real problems;

top: everything proceeds according to our plan."

Page 75: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Level in hierarchy often equates with rank / rewards

Engineers either cannot rise in level or are forced to abandon their primary skills to be managers

2.2 Matrix OrganizationStaff are assigned specialized roles based on skill sets

e.g., architects, designers, analysts, testersTeam managers address general ability of team to perform role

Subprojects identify required role playersTeams with commonly required roles move among multiple subprojectsProject managers oversees specific project

Roles/TeamsSub-systems Coding Architecture Analysis Testing GUI

A Y Y Y YB Y Y Y YC Y Y YD Y Y

Clearly this has limited benefit if an organization is so small that they have just one architect, one tester, …

In this model, team members with critical skills can be swapped from project to project depending on where each project is within the SDPM. For example, agood architectural designer may leave projects once they enter the high-level design phase.

Dangers of Matrix Organization

Restricted inter-role communicationManagement clashes

project managers may clash with the higher managers that assign people via the matrix.

3 Software Team OrganizationsAnarchy, hierarchy, and matrix are all pretty generic forms.

Next we look at some specific organizations that have been attempted.

Page 76: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.1 Chief Programmer TeamsMills (1970)

Motivated in part by studies showing vast differences in productivity between different individuals within an organization

Programming productivity studies have found that the “best” people in many organizations were orders of magnitude more productive than the average.(Not than the worst, but than the average.)

Some of this correlates with varying degrees of experience, both in general and with the specific problem domain and development environment at hand.But some of this seems to indicate that some people just are better at this than others.

Aims to allow the potentially most productive people to work unhindered

Organization of the Chief Programmer Team

Chief programmer is team leaderresponsible for design and critical parts of the implementation

Assistant programmer assists chief and does rest of the implementationLibrarian handles documentation, deployment, code management, etc.A few specialists can augment the team

Observations

A very coding-centric viewHigh stress on chiefLow level of satisfaction for remainder of teamDoes not scale well to large projects.

3.2 SWAT TeamsSWAT == Skilled With Advanced Tools

A team organization for iterative process models

Small team, sharing a common workspaceHeavy tool supportTeam leader is “first among equals”

Page 77: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.3 Agile TeamsSmall teams, often sharing a workspace

Typically, one team manager

Often includes customers/stakeholders or their designated representative as a team member.Team sets their own best practices

selects toolsEmphasis on self-management, self-motivation

Professional pride

3.4 Distributed TeamsCommon in open-source development

Small core team responsible for project “vision”Associated developers submit patches, changes, etc.

Must be approved by core team to be merged into official projectA pull request is a request for others to check out a proposed change.

Users submit bug reports and feature requestsMay be prioritized by core team.But an associated developer is not prohibited from working on a low-priority request.

Total team can be huge and diverse.

Closing Thoughts

If you were formed into groups, this week, to work on a project, how would you organize yourselves?

Would it match any of the organizations shown here?

Does it make a difference to your answer whether this is a distance course?

Page 78: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

High-Level Design: A Quick OverviewSteven J Zeil

Last modified: Jan 29, 2020

Contents:1 Levels of Design2 Modeling Classes

2.1 Attributes2.2 Operations2.3 Relations

3 Classification3.1 How Do We Discover Classes?3.2 How Do We Discover Relationships Among Classes?3.3 Keep It Real!

Abstract

High-level design is the process of breaking a large system into smaller manageable pieces that can work together to solve a larger problem.

This lesson presents a quick overview of classification, the dominant approach to high-level design.

1 Levels of DesignSoftware design is largely deivided into

Architectural Designglobal decisions that affect nearly all components of a system.

High-Level Designthe division of a system into modular components

Low-Level Designthe selection of data structures and algorithms to implement an individual component

CS361 emphasizes this level of design

CS330 emphasizes high-level design

Page 79: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

if you have taken CS330, most of this lecture will be review for you.

CS361 emphasizes low-level design

In current practice, the primary type of “component” that we seek is the class.

The process of discovering such classes is classification, and that is what this lesson will concentrate on.

2 Modeling ClassesWe model classes by focusing on

attributesthe data components that conceptually make up or are “contained” within a class

methodsa.k.a. operations, the things we can to do to object of that class

relationshow does this class interact with the other classes in our design?

2.1 AttributesAn attribute of a class is a data property that is conceptually a part of that class.

For example, we might say that an duration or elapsed time can be broken down into hours, minutes, and seconds. Shown on the right is a UML diagram for aclass with those three attributes.

2.1.1 Attributes Data Members

One possible realization of this class would be to indeed represent attributes as data members:

class Duration { public: int hours; int minutes; int seconds; }

Most class designers would balk at this however, preferring

Page 80: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

class Duration { private: int hours; int minutes; int seconds; public: ⋮ int getHours() const {return hours;} void setHours (int h) { hours = h; } int getMinutes() const {return minutes;} void setMinutes (int m) {minutes = m; } int getSeconds() const {return seconds;} void setSeconds (int s) { seconds = s; } }

Both of these are perfectly reasonable realizations of the idea that “a duration of time has attributes of hours, minutes, and seconds”.

This is another perfectly reasonable realization of that idea:

class Duration { private: int secondsSinceMidnight; public: ⋮ int getHours() const {return secondSinceMidnight / 3600;} void setHours (int h); int getMinutes() const {return (secondSinceMidnight % 3600) / 60;} void setMinutes (int m); int getSeconds() const {return secondSinceMidnight % 60;} void setSeconds (int s); }

This implementation might be favored if we expect to do a lot of calculations on durations (e.g., adding times together).

This demonstrates that we can have the logical idea of an attribute that does not reflect the eventual data members. All of these possible implementations arestill represented by the same UML diagram.

2.2 OperationsOperations are things we do to/with an object that are conceptually more complex than simple storage and retrieval.

Page 81: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

It makes sense, for example, to add one duration to another. E.g., if I listen to a music track that takes 4 minutes, then another that takes 3 minutes and 30seconds, then I have spent a total of 7 minutes, 30 seconds listening to music. Similarly if I say that one track takes 4 minutes and another takes 30 seconds lessthan the first, I should be able to compute the acutal duration of the second track by subtraction. I might also want to allow multiplication by an integer so thatwe could work with concepts like “twice as long as”.

In programming terms, operations will map onto public function members. (It is possible to model private members in UML, but that is generally reserved forthe very late states of design.)

It’s possible to have classes that have the same attributes but different operations (and vice-versa).

Another idea of “time” is that of the time of day – a particular instant in time rather than a duration. The attributes are the same, but the operations would bedifferent. It does not make any sense to add one time of day to another – you can’t add 12:30PM to 4:00AM and expect that to actually mean anything. But youmight add a duration of 30 minutes to 12:30PM to figure out what time it is if you arrive for an appointment at 12:30PM and have to wait for 30 minutes.

2.3 RelationsSo far we have talked about what is “inside” a single class. Relations describe important properties between pairs of classes.

2.3.1 Associations

The most basic form of relation is the association, which is simply any named relationship that we wish to discuss or focus on. We read these connections asmeaning

there is a TimeOfDay associated with an Event that tells us when the event starts, andthere is a Duration associated with an Event that tells us how long the event takes".

Associations are very general, so much so that, without the label identifying what we mean by them, they would be too vague to be useful.

But when it’s time to write the labels for an association, there are a few of labels that occur so often in practice that they merit their own UML visual signal:

2.3.2 Aggregation

This new relation is aggregation, and can be read as “an Agenda is part of an Event” or “an Event has a(n) Agenda”.

As a general rule, aggregation relationships could be rewritten as attributes:

This…

…and this…

Page 82: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

…mean pretty much the same thing.

Not all attributes, however, can be rewritten as aggregation.

Sometimes we prefer to use the aggregation arrow to make the relationship stand out.

If we think it’s important to our discussion, we may want to make the relationship more visible.

Aggregation is somewhat stronger than an attribute.

For example, I might be OK with this notion of a Student being an attribute of an ID card.

But I have a real problem with the idea that a Student is “part of” an ID card. We don’t press students flat and laminate them onto a piece of plastic!

Now, late in the design phase, when we are clearly talking about programming language classes rather than real-world constructs, I might toleratethis form of aggregation.

2.3.3 Inheritance / Generalization / Specialization

In many real-world scenarios, we encounter pairs of classes where one class is a specialized form of the other. In programming languages, this is referred to asan inheritance relationship, and could be denoted as an association labeled as “specializes” or (in the other direction) “generalizes”, or, more simply “is a”.

For example, we might say that a Duration is a kind of “time”, and a TimeOfDay is another kind of time.

This diagram, for example, captures the ideas that

All variations on the idea of “Time” will have same attributes – hours, minutes, and seconds.Duration and TimeOfDay are specialized forms of Time.Duration and TimeOfDay each have operations that are not common to one another not common to the general idea of Time.

3 ClassificationThe Object-Oriented design philosophy states that

Every program is a simulation, and the quality of a program’s design is directly proportional to how faithfully it mimics the objects in the worldbeing simulated and the way in which those objects interact.

Object-oriented design is all about designing software whose structure mimics the real world.

Page 83: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.1 How Do We Discover Classes?We do not invent classes,We discover them by examination of the world in which the software will reside.

Remember, first and foremost, that classes are groups of objects and objects are things.

3.1.1 Look for “Things”

Look through the available documentation on the problem you are trying to solve. Talk to people who work in that world.

Look for the kinds of things (nouns or noun phrases) that get mentioned over and over in discussion the problem area.

If you can’t have a meaningful discussion about the problem without mentioning a thing of some kind, that “kind of thing” should be one of your classes.

3.2 How Do We Discover Relationships Among Classes?Look through the available documentation on the problem you are trying to solve. Talk to people who work in that world.

Look for descriptions of how things interact.

Verbs and verb phrases that occur repeatedly in any discussion about the problem are suggestive of operations, particularly when they describe somethingthat is happening or changing.

“Next we schedule the meeting at the agreed-upon time.”

“We compute the total time of all the tracks onthe album.”

Verbs and verb phrases that describe how things are rather than howthey are changing may be suggestive of relations and/or attributes.

“The meeting starts at a specified time and lasts for a predetermined amount of time.”

“The duration of a meeting can be expressed in terms of hours, minutes, and seconds.”

3.3 Keep It Real!Example: We have been tasked with automating the means by which public library patrons find books in the library.

We “know” that we will be using a database to permit searches for books.

Page 84: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Nonetheless, it is a mistake to design a LibraryDatabase class.

Because no one walks into a library, sees a large box labeled “Database”, and says “Ooo, let me look at that.”

Instead we would design a Catalog class.

Because many generations of library patrons have walked in to a library, moved to the “card catalog”, and searched though it for relevant books.

We discover this class in the real world, and model it in our design.

It is entirely possible that the data structure and algorithms used for low-level design of the Catalog will be that same database, but that’s a hidden,private decision.

From examination of the physical catalog, we learn that traditional searches have been supported by author, by title, and by subject keyword.

This informs our interface design for the Catalog class in a way that might not have been obvious if we jumped directly in with a Database.

Page 85: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Network Conferencing: Google MeetSteven J Zeil

Last modified: Jan 20, 2020

Contents:1 Between Four and Seven Days Before Your Recitation Section2 Between 72 and 48 Hours Before Your Recitation Section

2.1 Possible Assignments3 Between 1 and 24 Hours Before Your Recitation Section4 At Least 15 Minutes Before Your Scheduled Meeting5 During Your Meeting6 After the Instructor Leaves

6.1 Screen Sharing6.2 Document Sharing6.3 Diagram Sharing

In this course you will be working in teams, and your team members might not be able to meet with you in person. Although email, forums, and wikis can servefor much communication, there will be times when you need to talk “synchronously”

This is a mandatory exercise exploring options in network conferencing. It will count as an assignment in the course grades.

You will need a PC with a good internet connection, a microphone, and headphones for this exercise.

Headphones, not speakers! Even if it’s just a pair of earbuds you normally use for listening to music.

When you use speakers, there is a significant chance of the sound from your speakers being picked up by your microphone and sent out to everyone in theconference. At best, this creates an unpleasant echo effect. At worst, it creates feedback making the audio useless for everyone.

1 Between Four and Seven Days Before Your Recitation Section1. Navigate to your recitation section (not the lecture section)in Blackboard. In the “My Groups” area, you should see that you have been added to a

“WebConference…” group. Enter your group’s Discussion Board.

If you are the first person here, create a new thread titled “Counting Off”. Post your @odu.edu email address.

Each subsequent person should reply to that post, adding their ODU email address.

Page 86: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2. Check the system reqts for the machine you expect to use for conference meetings in this course.

Note in particular that you will need to use the Chrome or Firefox browsers. In particular, Internet Explorer, Edge, and Safari are not supported.

2 Between 72 and 48 Hours Before Your Recitation Section1. Return to your group’s discussion board in Blackboard.

The instructor will have replied to that thread, giving each person there an assignment. Carry out your assignment.

2.1 Possible Assignments

2.1.1 Meeting

If your assignment is “Meeting” followed by a time, your task is to set up a meeting and invite your team and the instructor to it.

1. Navigate to calendar.google.com and log in with your ODU account.

2. Navigate to the day of your recitation. Click on the time slot closest to the start of your recitation, dragging the box down to the scheduled end time ofyour recitation.

A “New event” box will pop up. Click the “More Options” button to get to the detailed page.

3. Complete the meeting setup by supplying the requested information.

A. Enter a meaningful name for the Event (e.g., CS 350: Group 1 Meeting).

B. Edit the start and end times, if necessary to match your assigned time and the end of the recitation period.

C. If you see an “Add Conferencing” button in the place of the “Hangouts Meet” indicator shown here, click that to add the video conference.

D. In the “Add guests” area, enter the ODU email addresses for each of your teammates ([email protected]) (get these from the group discussionboard) and click add.

A. You may find that Calendar offers to auto-complete some of these for you.

B. Also add the instructor’s email, [email protected], to the invitation list.

Page 87: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

It’s important that youinvite the instructor (andyour teammates) via [email protected] email address,not an @cs.odu.edu orpersonal GMail account.

4. Click “Save” when you are done.Invitations will be sent to all of thegroup. These will include a linkallowing direct access to theconference.

2.1.2 Document

If your assignment was “document”, then

1. Go to Google Drive, which you can select from the Google Apps button . Make sure that you are logged in with your @odu.edu credentials.

2. Create a new Google Doc document. Copy and paste a few paragraphs from this web page into that document.

3. Click in the title area and give your document/drawing a title. Include “CS350 document” and your group name/number from Blackboard in the title.

4. Exit the document and return to the Drive directory page.

5. Right-click on your new document/drawing and select “Share…”. Enter the email addresses of your group members with “Can Edit” permission.

Also add the instructor’s email, [email protected], to the shared list.

It’s important that you share via an @odu.edu email address, not an @cs.odu.edu or personal GMail account.

Page 88: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.1.3 Diagram

If your assignment was “diagram”, then

1. Go to Google Drive, which you can select from the Google Apps button . Make sure that you are logged in with your @odu.edu credentials.

2. Create a new Google Doc document.

3. Click in the title area and give your document/drawing a title. Include “CS350 diagram” and your group name/number from Blackboard in the title.

4. In the “Add-Ons” menu, select “Get add-ons”. Search for “PlantUML Gizmo” and install it.

5. In the “Add-Ons” menu, select “Plant-UML Gizmo”, “Start”.

6. Add a few empty lines to your document, then position the cursor in the middle of them.

In the Gizmo editor pane, select “Observer class structure”, then click Insert to place a diagram into your document.

7. Exit the document and return to the Drive directory page.

8. Right-click on your new document/drawing and select “Share…”. Enter the email addresses of your group members with “Can Edit” permission.

Also add the instructor’s email, [email protected], to the shared list.

It’s important that you share via an @odu.edu email address, not an @cs.odu.edu or personal GMail account.

3 Between 1 and 24 Hours Before Your Recitation Section1. Check your email. You should have received at least one invitation to participate in a Google Meet session. One will be from the instructor. Others may

be from your teammates for this exercise.

2. As an ODU student, you have a Google account for your @odu.edu email. This is what you must use to participate in all class-related meetings. Log intoyour ODU email to be sure that your browser is logged in under your ODU account rather than any personal GMail/Google account that you might alsohave.

You may want to explicitly logout of your personal GMail account before logging into your ODU Account

3. In a separate tab/window, check your Google calendar. You should see the event listed there.

4. Links in the email and calendar entry will allow you to indicate whether you plan to attend. Click on one to indicate that you plan to attend.

Page 89: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

5. Check the system reqts for the machine you expect to use.

Note in particular that you will need to use the Chrome or Firefox browsers. In particular, Internet Explorer, Edge, and Safari are not supported.

6. Go to Google Drive, which you can select from the Google Apps button . Make sure that you are logged in with your @odu.edu credentials.

You should see at least one “CS350 document” and at leat one “CS350 diagram” has been shared with you.

7. Open one of the diagrams.

8. Install the PlantUML Gizmo: In the “Add-Ons” menu, you may already see an option to install it. If not, select “Get add-ons”. Search for “PlantUMLGizmo” and install it.

4 At Least 15 Minutes Before Your Scheduled Meeting1. Again, log into your ODU email to be sure that your browser is logged in under your ODU account rather than any personal GMail/Google account that

you might also have.

2. Enter the meeting by using the “Join Hangouts Meet” link in the invitation email or in the calendar entry.

3. If this is your first time using Meet video conferencing, you may be prompted to load a browser plugin. If not, but all that you see is a large green “speechbubble” with quotations marks inside it, click on it and you may be prompted to install the browser plugin.

4. Wait for your group members to arrive.

5. (Optional) If you have time before the meeting starts, you may start the After the Instructor Leaves portion of this exercise.

5 During Your MeetingWhile you wait for the instructor,

1. Note that each person has control over which person occupies the large central area of the call window on their own screen. Simply click on one of thethumbnail images at the bottom of the call to bring up that person. Try this a few times.

2. At the bottom center of your screen, you should see your main meeting controls.

These allow you to

Page 90: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A. Mute or activate your microphoneB. Leave the callC. Turn your camera on and off

Try the microphone and camera controls out. Note that etiquette in network conferences is to mute your microphonewhen you are not speaking. This reduces the amount of background noise that everyone must deal with. It also reduces the chances of echoing andfeedback.

In very large conferences (more than a half dozen or so people), it’s also common to switch one’s video feed off when not speaking or actively engaged inthe conversation. Turning your video back on is then a signal for attention, rather like raising your hand in class.

3. In the upper right corner, you should see a small control area. (You may need to click on the control area to expand it)

Clicking on the chat box at the top right will drop down a text chat window, useful is someone’s microphone is not working. It’salso useful for doing things like sending a URL to other people so they can copy-and-paste it into their browser.

4. Near the bottom right of your screen, you can find another important control.

The “Present Now” button allows you to do “screen sharing”, presenting your entire screen or a specific window to the otherparticipants. You’ll play with that more in just a bit.

5. Your instructor will join you briefly near the beginning of your scheduled session.

Once the instructor joins, he may ask you all to leave and rejoin in a meeting session scheduled by one of the team members instead of the one created bythe instructor. If so, meet him there.

6 After the Instructor Leaves6.1 Screen SharingPractice screen sharing and get yourselves set up for future recitation discussions:

Page 91: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

One by one, take turns doing the following:

1. Use the “Present Now” control to turn on screen sharing.

You will be given a choice of what to share: your entire screen or just selected windows.

If you are the first person to take a turn, share your entire screen.

If you are the second person to take a turn, share your web browser.

After the first two people have tried, the remainder may share either their entire screen or their web browser.

2. Ask your team-mates to describe to you what they see from your PC. In particular, can they read the text in your window(s)?

If you are sharing just your web browser window, try resizing the window at full-screen and to just half the screen height and width. Ask your teammateshow this affects what they see.

3. Right-click on a line in your web-browser to bring up a pop-up menu. Tell your team-mates what you have done and ask them to again describe to youwhat they see from your PC.

4. Click on a menu in your web-browser to drop down a list of menu entries. Tell your team-mates what you have done and ask them to again describe toyou what they see from your PC.

6.2 Document Sharing1. You should have at least one document shared with you in Google drive by a team member. Go to Google Drive and open that document (in a separate

tab/window). Click somewhere in the document.

As everyone opens the document, you should see “cursors” for each person. Everyone should add their name to the document. (Don’t wait to take turns –just move your cursor to a clear spot and type your name.)

Once all the names are typed out, arrange them into a bulleted list near the top of the document.

Notice how updates can be seen simultaneously at different locations.

You can play around a bit with other edits, but leave the list of names intact.

(You can do the same kind of thing with Google Drive shared documents outside of video calls as well. But the ability to edit simultaneously is aninteresting and unusual feature.)

6.3 Diagram Sharing

Page 92: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The PlantUML Gizmo allows you to work together on design diagrams.

Collaborating is not quite as smooth as in the basic Google Doc you just practiced with. The key elements to remember are:

Selecting an image and then clicking Edit selected gives you a private copy of the text that defined the diagram.

You can edit that to your heart’s content, watching what happens in the Preview area.

No one else sees your Preview area.

Clicking Insert replaces the diagram that everyone sees in the document.

If you have do not have a diagram selected in the main document when you do this, it insets a new diagram at your cursor.

Collaborating on single large document in this way would be awkward. But a large document with many small diagrams is quite manageable.

Working together, convert the initial diagram into this:

1. Identify a single change to be made to get closer to your goal. Let one person announce that they are going to do it.

2. That person should select the diagram, click Edit selected, carry out the change, and then click Insert to post the change to everyone else.

3. Repeat the above two steps as necessary, with different people taking turns carrying out the changes.

Some notes on the required changes:

Class diagrams in PlantUML typically start with a description of the classes involved, using a C++/Javaish notation.

That is followed by descriptions of one or more connecting arrows.

An arrow has the name of two classes on either side of “–” for a solid line, “..” for a dotted line.You can add various characters to one or both ends of the “–” or “..” to set the type of arrow head.

Page 93: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

For our purposes, try ‘o’, ‘<’ or ‘>’, ‘<|’, and ‘|>’. E.g., “o–>”.

You can add a direction inside the arrow assembly, e.g., “<-left-”, to indicate the direction you want the line to go. This actually rearranges the classboxes to accommodate your selection.

You can attach a label to an arrow by following the entire classnames-and-arrow assembly with a colon, a space, and then the desired label.

You can follow the label with a blank and then either ‘<’ or ‘>’ to add a direction marker.

Here’s a quick guide to the the PlantUML notation for UML class diagrams.

Delete the line “hide empty members”. (It produces more compact, but technically non-standard UML.)

I prefer “Observable” to “Subject”, both because it is more descriptive and because the classes Observer and Observableare part of the standardJava API. ButSubject` is the original term popularized in Design Patterns, the groundbreaking book by Gamma et al.

CS330 folks should recognize the components of these UML class diagrams. For the rest of you, we’ll have a quick look at what these actually mean later in thesemester.

1. Optional: if you have the time and the inclination, try this tool for doing UML diagrams collaboratively within Google drive.

Draw.io handles collaboration more smoothly than the PlantUML, but there’s a lot of very basic UML stuff that is impossible or, at least, tricky to drawwith it.

Leave your shared documents and diagrams in place until a grade has been posted for your participation in this recitation.

Page 94: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Eliciting RequirementsSteven J Zeil:

Last modified: Dec 21, 2019

Contents:1 Basic Principles of Requirements Analysis2 Eliciting Requirements3 Obtaining Requirements Information

3.1 Interviews3.2 Prototyping

4 Organizing Requirements Information4.1 Viewpoint Analysis4.2 Use Cases4.3 Object-Oriented Analysis

Abstract

Eliciting requirements is the process of determining what the customers actually need a proposed system to do and of documenting that information in a waythat will allow us to write a more formal requirements document later.

In this lecture we survey some key concepts, problems, and actitivies associated with requirements elicitation, and then look at use cases, one of the mostpopular ways of documenting our understanding of those requirements.

1 Basic Principles of Requirements AnalysisUnderstanding the customer’s requirements for a software system

Developers working with customers to find out about the application domain, the services that the system should provide and the system’s operationalconstraints

May involve end-users, managers, engineers involved in maintenance, domain experts, trade unions, etc. These are called stakeholders

Problems of requirements analysis

Stakeholders don’t know what they really want

Page 95: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

(Is this a real problem, or snobbery on the part of software developers? For as often as I see this “problem” listed, I’m never really sure.)

Stakeholders express requirements in their own terms

Different stakeholders may have conflicting requirementsOrganizational and political factors may influence the system requirementsThe requirements may change during the analysis process.New stakeholders may emerge

2 Eliciting RequirementsThe process of eliciting requirements is, fundamentally, an exercise in communication between developers and stakeholders.

Problem 1: Obtaining informationProblem 2: Organizing the information obtained

3 Obtaining Requirements InformationCommon sources are

Reading available documentation

Interviewing the stakeholders…

Facilitated meetings

(i.e., gather the stakeholders around a table for a formal discussion).

Prototyping…

Direct observation (a member of the development team)

A member of the development team physically observes the current process in operation.

3.1 InterviewsInterviews may focus on general questions, e.g.,

“What do you do? ”What information do you need to do your job?“, ”What problems are you encountering with the current system?"

Page 96: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Or may seek to elicit scenarios

“Walk me through the process you follow when X happens.”

These interviews can be as much about learning how the current system works as about what is desired from the new system.

That’s consistent with object-oriented approaches where a domain model is constructed of how the system works now, and that model is graduallyevolved into an analysis model of how we would like it to work in the future,

including the possible automation of processes currently done manually.OO practice assumes that the structure of the new system will mirror the structure of the old one to a significant degree, so effort spent modelingthe current world is also effort towards modeling the new system.

3.2 PrototypingBuilding a quick mock-up of the eventual system

May ranges from paper mockups of screens to beta-test codeProviding or displaying the prototype to the stakeholders

It can be an effective method to

Validate our understanding of the requirementsElicit discussion on things that we mis-understood or failed to consider at all.

4 Organizing Requirements Information4.1 Viewpoint Analysis

Stakeholders represent different ways of looking at a problem or problem viewpoints.This multi-perspective analysis is important as there may be no single correct way to analyze system requirements.

By approaching requirements from multiple viewpoints, we can identify conflicting requirements among the stakeholders.

4.1.1 Types of viewpoint

Viewpoints are perspectives on the system, not “people who view it”.

Common viewpoints include

Data sources or sinks

Page 97: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Viewpoints responsible for producing or consuming data.

Representation frameworks:

Viewpoints representing particular types of system model.

May be compared to discover requirements that would be missed using a single representation.

Receivers of services:

Viewpoints external to the system that receive services from it.

Particularly useful for interactive systems

4.1.2 The VORD method

VORD: Viewpoint-Oriented Requirements Definition

Viewpoint identificationDiscover viewpoints which receive system services and identify the services provided to each viewpoint

Viewpoint structuringGroup related viewpoints into a hierarchy. Common services are provided at higher-levels in the hierarchy

Viewpoint documentationRefine the description of the identified viewpoints and services

Viewpoint-system mappingTransform the analysis to an object-oriented design

Example: Checkbook balancing

Consider the design of software to balance a checkbook:

should accept transactions including

checksdepositswithdrawalsinterest accruedservice charges

Allow transactions to be confirmed from bank statement

Page 98: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

should show current and confirmed balances

Viewpoint Identification

Plausible viewpoints are:

AccountBankAccount HolderClearing House

Services Provided

Account

apply transactions

Bank

create/close accountsreceive transactionsinitiate transactions (charges)

Account holder

receive account statementinitiate transactionsexamine register entriesget statement balanceget confirmed & unconfirmed register balancesconfirm transactions from statement

Clearing House

receive checks

Viewpoint Documentation

Page 99: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

For each viewpoint, we document the data and services that are visible form that viewpoint.

Reference: Bank

Attributes: name, location, accounts list

Events: end-of-month, transaction arrival

Services:

create/close accountsreceive transactionsinitiate transactions (charges)

Sub-VPs:

And we document the services

Reference: receive transaction (account debit)

Rationale: electronic funds transfer, may be signal from clearing house of a check received

Specification: The account balance is checked to determine if adequate. If so, confirmation of the transaction is sent, the account balance is reducedby the transaction amount, and the transaction noted in the account log. If not, the account kind is consulted for overdraft policy, and the policyroutine found there is invoked.

Viewpoints: Bank, Clearing House

NF Reqts: Response of confirmation, rejection, or unable-to-process must be made within 30 seconds, with a mean response less than 0.1 seconds.

Viewpoints: Bank

4.2 Use CasesUse cases have become popular as a means of organizing requirements.

Often includes in requirements documentsSpecific requirements are often linked back to a use case that explain or justifies them.

Page 100: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A use case is a collection of scenarios.

It depicts a functionality of the system,typically beginning with some external input or action.

It provides a step-by-step description of a main (success) scenario path.It includes extensions / alternative paths.

4.2.1 Writing Use-Cases

1. Start with a collection of scenarios2. Group by common user goals3. Define the actors4. Give brief descriptions of use cases5. Give a detailed description of the basic path6. Add alternative paths

Example: grading tests

Grading an Assessment

Actors: Scorer

Main Path

1. The scorer begins with an assessment and a collection of response documents.

2. For each item in the assessment, the scorer obtains the item’s rubric. Then for each response document, the scorer goes to the item responsefor that same item, grades the response using that rubric, and adds the resulting score and (if provided) feedback to the result document forthat response document.

3. When all items have been graded, then the scorer computes a total score for each results document.

4. The scorer add the score from each result document to the grade book.

Alternative: Candidate by Candidate Scoring

2: For each candidate, the scorer goes through each of the items. For each item, the scorer obtains the item’s rubric, grades the item response usingthat rubric, adds the resulting score and (if provided) feedback to the result document for that response document.

Page 101: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Example:

Get Paid for Car Accident

Actors: Claimant, Accident victim making claim, Insurance Company, Company insuring Claimant, Agent, Insurance Company representative>processing claim

Main Success Scenario

1. Claimant submits claim with substantiating data.2. Insurance Company verifies that Claimant owns a valid policy.3. Insurance Company assigns Agent to examine case.4. Agent verifies that all details are within policy guidelines.5. Insurance Company pays Claimant.

Extensions

1a. Submitted data is incomplete:

1a1. Insurance Company requests missing information. 1a2. Claimant supplies missing information.

2a. Claimant does not own a valid policy:

2a1. Insurance Company declines claim, notifies Claimant, records all this, and terminates proceedings.

3a. No Agents are available at this time:

3a1. (What does the Insurance Company do here?)

4a. Accident violates basic policy guidelines:

4a1. Insurance Company declines claim, notifies Claimant, records all this, and terminates proceedings.

4b. Accident violates some minor policy guidelines :

4b1. Insurance Company begins negotiation with Claimant as to degree of payment to be made.

(Adolph)

4.2.2 Components of a use case

Lots of local variations:

Page 102: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. Title

2. Overview – natural language description

3. Actors – list of external entities participating in the use case

4. Preconditions – list of conditions that must be true before this use case can be invoked.

5. Scenario(s): specified as a main path and a collection of alternative paths

6. Postconditions – list of conditions that are expected to be true upon completion of the use case

7. Exceptions – List of failure conditions associated with the scenarios, and the appropriate system responses

Of these, #1 and #5 are essential and universal.

#4, #6, & #7 are often empty

Pre-conditions are generally omitted if trivial (always true)Exceptions can often be re-written as alternative pathsPost-conditions are often omitted because he desired non-trivial conditions may only hold if the main path succeeeds.

Example

Attempt Assessment

Overview: A candidate attempts to take an assessment. The candidate might or might not finish the assessment within a single session.

Actors: candidate, proctor

Preconditions:

1. Assessment has been created2. Assessment has been provided to the proctor

Main Path:

1: A candidate indicates to a proctor their desire to take an assessment. (This may involve simply showing up at a previously-schedule time andplace when the assessment is going to be available.)

2: The proctor provides the candidate with a copy of the assessment and an empty response document.

Page 103: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3: The proctor authorizes the start of the assessment session.

4: The candidate reads the assessment, and repeatedly selects items from it. For each selected item, the candidate creates a response, adding it to theresponse document.

5: The proctor ends the assessment session after time has expired.

6: The candidate returns the response document to the proctor.

— Alternatives

Unavailable

2: The proctor determines that the candidate is not eligible to take the assessment at this time (the assessment is not available or the candidate hasnot fulfilled assessment requirements such as being enrolled in the course).

The use case terminates immediately.

Variant Assessments

2A: Proctor randomly selects one of multiple available variants of the assessment.

2B: The proctor gives that selected assessment and an empty response document to the candidate.

In-line answers

2: The response document and the assessment copy are a single document.

Candidate provided response document

2: The candidate brings blank sheets of paper or blue books to serve as the response document.

Candidate finishes early

5: The candidate indicates that he/she is finished prior to the end of the allotted time. The proctor ends the assessment session.

Suspended session

5: The candidate asks to suspend the session, with the intention of completing the assessment at a later date. The proctor determines from theassessment properties that this is acceptable.

6: The proctor collects the candidate’s response document and copy of the assessment.

Page 104: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4.2.3 Quality Use Cases

Good use cases are

Written in customer languageValidatableFocused on a single goalExpress requirements, not design

A poor use case

Register for Course

1. Display a blank schedule.2. Display a list of all classes in the following way: The left window lists all the courses in the system in alphabetical order. The lower window

displays the times the highlighted course is available. The third window shows all the courses currently in the schedule.3. Do4. Student clicks on a course.5. Update the lower window to show the times the course is available.6. Student clicks on a course time and then clicks on the “Add Course” button.7. Check if the Student has the necessary prerequisites and that the course offering is open.8. If the course is open and the Student has the necessary prerequisites, add the Student to the course. Display the updated schedule showing the

new course. If no, put up a message, “You are missing the prerequisites. Choose another course.”9. Mark the course offering as “enrolled” in the schedule.

10. End do when the Student clicks on “Save Schedule.”11. Save the schedule and return to the main selection screen.

Problems:

Too much user interface detail (design)

Too low level.

Written more from system’s perspective than from customer’sUnclear pseudo-code-ish structure

Poor grammar.

Improved Version

Page 105: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Register for Course

1. Student requests a new schedule.2. The system prepares a blank schedule form and pulls in a list of open and available courses from the Course Catalog System.3. Student selects primary and alternate courses from the available offerings.4. For each course, the system verifies that the Student has the necessary prerequisites and adds the Student to the course, marking the Student

as “enrolled” in that course in the schedule.5. When the Student indicates the schedule is complete, the system saves the schedule.

4.2.4 Use Cases and Requirements

We will shortly see that common requirements documents are

Reqts Definitions, andReqts Specifications,

the latter being more detailed and formal.

Use cases fall somewhere between the two, and are often used as a mechanism for gathering the additional details needed to write the specifications.

4.3 Object-Oriented AnalysisThe Object-Oriented philosophy can be summarized as:

Every program is really a simulation.

The quality of a program’s design is proportional to the faithfulness with which the structures and interactions in the program mirror those inthe real world.

In pre-OO, Waterfall and similar processes, at the end of each phase, we set aside the prior set of documentation and sit with blank sheets of paper to begin thenext phase “fresh”.

The records of elicited requirements information serve as references when we start writing the requirements documents.

The requirements documents serve as references when we start writing the design documents.

The design documents serve as references when we start writing the code.

Page 106: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

But each new step is, in essence, a fresh start.

There’s a certain wisdom in this. There’s a real danger in making design decisions when writing early requirements, or in having people reading therequirements think that you made a design decision when choosing notations or writing explanations as part of the requirements.

A fresh start helps remind designers that they have the freedom, if not the obligation, to consider alternatives.

Evolution

But the OO view is very different. If we buy into the OO philosophy, then we take a more evolutionary process.

OOA is largely viewed as a model-building activity:

Start with a model of how the world works now.Make just enough changes to that model to explain what we want to change (e.g., via new automation).Make just enough additional changes to account for necessary design “compromises”.

The result is, eventually, a design that had clear ties to the original model of the world before we started our project.

Model Building

The primary models of Object Oriented Analysis and Design are:

domain model

analysis model

design model

4.3.1 Domain Models

A domain model is a model of the application domain as it currently exists, before we began our new development project. The point of the domain model is tobe sure the development team understands the world that the system will work in.

The domain model describes the world in terms of objects interacting with one another via messages.

Not every project needs a domain model

e.g., If the team has done several projects already in this application domain, they may already share a common domain model.

Page 107: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

(Fortunately, most companies work in a small number of application domains.If they hired you last month to develop software for analyzing seismic data forpetroleum engineering, they are unlikely to ask you to develop a compiler or aword processor next month.)

In that case, the team may already have a good understanding of the domain.

Even if a document describing the domain model is desired, domain modelstend to be highly reusable since the world around our software systems usuallychanges fairly slowly.

Interacting Objects

All OOA models are based on the concept of objects interacting with one another by the exchange of messages (function calls).

Hence, even if we are modeling a physical object or a human being, we write our models in terms of classes with an interface of attributes and operations.

E.g.,

Transactiondate number relatedAccount amountapply(toBalance)

CheckbookAccount

Page 108: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Balance list of Transactions add(Transaction) cancel(Transaction) balanceAgainst(Statement)

4.3.2 Analysis Models

An analysis model is a model of how the world will interact with the software system that we envision. As such, it is our statement of just what the system willdo when it is working.

There is a real temptation to simply assume that the automated system will simply squat in the middle of the world, interacting with all the real world objects,sort of like this:

Or if you prefer,…

Page 109: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

It’s Magic!

Poof! We have an analysis model!

Not wrong, per se, but it’s certainly not helpful.

Such an approach is fundamentally at odds with the OO philosophy, though.

We should look to the real world to suggest how to decompose our system.

In this case, we have not decomposed it at all – just wrapped it up into a single black box.

All the hard decisions still need to be made.

And we have thrown out any insight we gained from building our domain model.

In essence we have not done any analysis at all here. This “model” isn’t wrong, per se, but it’s certainly not helpful. We’ve basically thrown away everythingwe’ve learned in the domain model about how objects really interact. We’re treating the new program as a simple box, with no knowledge of its internalstructure, Essentially, we’ve just deferred all the hard questions to the upcoming design.

Page 110: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Evolving the Analysis Model

What we really hope for is an evolution from our domain model to our analysis model. The OO philosophy tells us that the classes and interactions of ourdomain model …

… should carry over into our analysis.

In essence, we hope to retain these classes, add more detail to our understanding of them, and to establish a boundary that tells us which of these classes andbehaviors will be automated, which will remain entirely unautomated, and which will have some portion automated while other parts remain external.

Page 111: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The Boundary

… establish a boundary that tells us which of these classes and behaviors will

be automated

remain external

be a mixture of the two

The system, then, remains a collection of interacting objects rather than an unstructured black box.

We may need to modify our class interfaces to reflect our new understanding, but we don’t need to discard them and start from scratch.

There’s a definite overlap in the purpose of a requirements document and of an analysis model. Some will regard the analysis model as a kind of requirementsspecification. In some projects, though, a requirements document will still be required as something for customers or management to sign off on. But theanalysis model is the basis from which the eventual requirements document is derived.

Page 112: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The evolutionary approach will carry forward, in an OO-style project, fromrequirements into design. When building the design model, we will start withthe classes (and their APIs/interfaces) and make merely the changes we deemnecessary for an effective design.

(OOA is covered in more detail in CS330.)

Could not parse reqts...skipping

Page 113: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Project Phase 1: Software Requirements SpecificationCS350

Last modified: Jan 21, 2020

Contents:1 Overview2 Phase 1

2.1 Software Requirements Specification2.2 Peer Evaluation

3 Mechanics3.1 Teams

4 Submission4.1 SRS Document4.2 Evaluation

1 OverviewThe project is divided into 5 phases

1. Software Requirements Specification

2. User stories

3. Version control, ADT documentation, build manager, unit tests, website/wiki

4. configuration management, continuous integration

5. Final implementation, code analysis, integration & system test

All five phases are team activities. The teams for this first phase will be randomly assigned. For the remaining phases, you will select your own teams.

One purpose of allowing teams is to distribute the workload. One purpose of requiring teams is to be sure that students can employ the relevant tools andtechniques taught in this course in a collaborative environment.

Individual team members should not feel they can safely sit back and let everyone else do the work. Nor should one gung-ho team member, however talented,grab all the work and do it all. As a team, you must take responsibility for making sure that all team members understand and practice the relevant tools and

Page 114: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

techniques.

2 Phase 12.1 Software Requirements SpecificationPrepare a Software Requirements Specification (SRS) document for this requirements definition.

Your SRS must follow the format of the IEEE 830 standard, available on the course Library page. For Section 3, you may use any of the alternativeorganizations from the Appendix A of that standard.

You must, however, in section 1.5 Overview, explicitly state which of those organizations you have selected.Make your choice wisely. If you are unfamiliar with Object-Oriented Analysis, for example, do not choose to organize your requirements by object/class.Pay attention to what is important and what is secondary in a requirements specification. The real heart of a reqts spec. is in Section 3. The other sectionsare supporting text whose purpose is to make Section 3 easier to understand.

Even within Section 3, there is the “core” of the actual functional requirements (typically, “The system shall …” statements) and there is supporting textto help introduce and explain those requirements.

I do not care how nice your supporting text is — if you never actually state the functional requirements, you will not score well!

Talk to each other! Don’t just assign everyone a section of the outline to write in isolation and assume they can all be stitched together the day theassignment is due.

Given the critical importance of section 3, I recommend that you divide responsibilities up in a fashion such that each team member makes acontribution (even if only proof-reading) to parts of that section.

2.2 Peer EvaluationAfter your work has been submitted, each team member must individually take the peer evaluation survey. The purpose of this survey is to assess the relativecontributions made by individual team members.

3 Mechanics3.1 Teams

Page 115: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

This is a team assignment. Teams have been assigned randomly. You can view your team (group) assignment as one of the SRS… groups in the Groups area onyour recitation Blackboard site.

These are not the same groups that you had for the Web Conferencing recitations!

Blackboard will allow you to email your team members for coordination purposes. Your team has also been provided with a Discussion Area, which you mayuse to facilitate your work. Both will be visible only to your team members and to me.

Keep in mind that you have access to Google Drive via your ODU email account. You might chose to work collaboratively via a shared Google Docs documenton that cloud drive.

4 Submission4.1 SRS DocumentPrepare your SRS as a PDF document, following these guidelines.

When you are ready to electronically submit your assignment, use the button below:

Submit this assignment

Only one team member must submit on behalf of your team. If you submit more than once, (e.g., you discover a mistake after submitting), only your LASTsubmission before the due date will be considered.

4.2 EvaluationEvaluations will be a combination of what the group has accomplished and how much each individual contributed to that group’s effort.

This phase will be graded as:

score = doc. quality * indiv

where:

doc. quality is an assessment of the completeness, correctness, and quality of the document submitted by the team.

indiv is a scaling factor for an individual’s effort. A normal effort level is 1.0. This factor will be raised or lowered by a combination of

Page 116: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

score on peer evaluation surveyswhether the individual contributed to the survey

Page 117: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Clean CodingSteven J Zeil

Last modified: Dec 18, 2019

Contents:1 What is Clean Coding?

1.1 Perspectives2 Principles

2.1 Code must Express its Intent2.2 Tests should always pass.2.3 Keep it small, keep it simple

3 Practices3.1 Meaningful names3.2 Limit your Scope3.3 Functions should do One Thing3.4 Error Handling is “One Thing”3.5 Avoid Duplication3.6 Distinguish between data structures and “true” objects3.7 The Law of Demeter3.8 Error Handling3.9 Classes should be small!

Abstract

Clean coding is a set of principles and practices aimed at producing code that is readable, trusted, and maintainable.

1 What is Clean Coding?In the end, we write code.

There are certain best practices that “good” programmers follow, maybe without even thinking about them, or maybe because they have learned, to their sorrow,that doing otherwise will cost them, even if only in time and effort.

Good code is

Page 118: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Readable

Trusted

Has it been tested?

How well?Does it pass?

Does it smell?

A code smell is a section of code that exhibits a practice that the programming community considers ill-advised or even dangerous.

Maintainable

Does the code throw barriers in the way of people trying to fix it or change it? e.g.,

Is the code highly coupled so that changes in one place directly affect many others?

Is code duplicated, so that fixes/changes need to be applied simultaneously to many different places?

1.1 Perspectives(from Martin, ch 1)

Grady Booch

Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer’s intent but rather is full of crispabstractions and straightforward lines of control.

Dave Thomas (OTI)

Clean code can be read, and enhanced by a developer other than its original author. It has unit and acceptance tests. It has meaningful names. Itprovides one way rather than many ways for doing one thing. It has minimal dependencies, which are explicitly defined, and provides a clear andminimal API. Code should be literate since depending on the language, not all necessary information can be expressed clearly in code alone.

.

Page 119: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Ron Jeffries

In priority order, simple code:

Runs all the tests;Contains no duplication;Expresses all the design ideas that are in the system;Minimizes the number of entities such as classes, methods, functions, and the like.

Ward Cunningham

You know you are working on clean code when each routine you read turns out to be pretty much what you expected. You can call it beautiful codewhen the code also makes it look like the language was made for the problem.

2 PrinciplesTests should always pass.Code should be expressive.

maximize cohesionKeep classes and methods small.Work at one level of abstraction.

Keep it small, keep it simpleMinimize coupling

Law of DemeterAvoid duplication.Do not create or maintain unnecessary code.

Closely related: SOLID design in OOP

SOLID is an acronym for a collection of design principles related to good object-oriented design.

Single ResponsibilityOpen-Closed PrincipleLiskov SubstitutionInterface SegregationDependency Inversion

Page 120: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The overall theme of SOLID is to control the ways in which different classes depend on each other. SOLID design tries to find class interfaces that are robusteven in the face of change.

We won’t delve into SOLID in this course, because it requires a certain grasp of object-oriented programming that is covered in CS330, and not everyone in thiscourse will have taken CS330.

But, if you are interested:

1. Martin: Agile Principles, Patterns, and Practices in C# chapters 8–12

2. SOLID Design (from CS330)

2.1 Code must Express its IntentMartin relates a story about replaying an editing session via an editor that captures the entire history of edits.

reveal +

Page 121: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Bob enters the module. He scrolls down to the function needing change. He pauses, considering his options. Oh, he’s scrolling up to the top of the module to check the initialization of a variable. Now he scrolls back down and begins to type. Ooops, he’s erasing what he typed! He types it again. He erases it again! He types half of something else but then erases that! He scrolls down to another function that calls the function he’s changing to see how it is called. He pops up another window and looks at a subclass. Is that function overridden?

Notice how much time is spent reading rather than writing.How much worse would this be if Bob had not touched this code in weeks, or months?

Or if Bob was not the original author of the code?

Code should be expressive of its intent.

2.1.1 Refactor to Improve

Refactoring is the process of making changes to code that make it more expressive, but that should not alter its behavior in any way.

Common examples of refactoring include:

renaming entitiesreplacing literal constants by named constant variablesreformatting codeencapsulating public data membersextracting blocks of code into separate functions.

Many IDEs (including Eclipse) have build-in support for these and other refactoring activities.

For example, renaming a function from the Refactor menu not only changes the name of the function in the declaration, but also of all calls to thatfunction in all source code files where it is used.

Page 122: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.2 Tests should always pass.We do not write large amounts of code and then get around to testing it (or claiming we had no time to test it).

We do not even write large amounts of code without pausing to rerun our tests every few minutes.

We’ll pass on the details for now, as we will be discussing automated unit testing and test driven development in great detail later.

2.3 Keep it small, keep it simpleMinimize the number of classes and membersAvoid duplicationEach function should “do one thing”.

3 Practices3.1 Meaningful names

int nCstCnt; // number of customers int numberOfCustomers;

There was a time when programmers could be forgiven for writing the code on the left.

Early programming languages limited variable names to a 5, 6, or 8 characters.FORTRAN used the first character to declare the type of a variable:

Names beginning with “I..N” were integers.Everything else was floating point.

The mechanics of punched cards encouraged the use of statements no more than 72 characters long.Keypunches and early text editors lacked support for automatic completion of partial variable names.

None of that is true any more!

So please stop writing code like I had to back in the late 1970’s – S. Zeil

Page 123: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.1.1 Good Names should…

Be expressive of the intention.

If you need a comment to explain what this thing is, you need a better name.

Be pronounceable

Draw meaningful distinctions.

Avoid tacking meaningless noise words like “Info”, “Data”, “Object”, …

What’s the difference between classes named Book and BookData?

Doesn’t every class actually provide data about something?

Avoid encoding type information.

Avoid variable names like songList.

Better to describe the intent as album, playlist, or discography.

Use appropriate parts of speech

Class, variable and constant names should be noun phrases.Method/function names should be verb phrases.

Avoid “nounifying” verbs.

generateSummaryReport is a perfectly good function name.It’s a terrible name for a variable or class.

And SummaryReportGenerator is hardly better.Better:

class SummaryReport { ⋮ void generateAndPrint(OutputDevice);

3.2 Limit your ScopeThe scope of a declared name is the range of code in which it can be legally referenced.

Page 124: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Place your declarations in as limited a scope as possible.1

This prevents accidental re-uses of the same variable name, including many uses that may interfere with one another.

3.2.1 Example (conditionals)

Don’t do this:

String firstName; String lastName; int pos = fullName.find(','); if (pos >= 0) { lastName = fullName.substr(0, pos); firstName = fullName.substr(pos+1); println ("Hello " + firstName + ' ' + lastName); } else { println ("Hello " + fullName); }

The scopes of firstName and lastName continue to run through the rest of this code block, till the end of the enclosing { }.

Do this instead:

int pos = fullName.find(','); if (pos >= 0) { String lastName = fullName.substr(0, pos); String firstName = fullName.substr(pos+1); println ("Hello " + firstName + ' ' + lastName); } else { println ("Hello " + fullName); }

Not only is there less chance of an accidental re-use of the names later, but there is also never a period of time in which the variables are uninitialized.

3.2.2 Example (for loops)

Don’t do this:

vector<Author>::iterator iter = authorList.begin(); while (iter != authorList.end()) { doSomethingWith(*iter);

Page 125: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

++iter; }

The scope of iter continues to run through the rest of this code block, till the end of the enclosing { }.

Do this instead:

for (vector<Author>::iterator iter = authorList.begin(); iter != authorList.end(); ++iter) { doSomethingWith(*iter); }

The scope of iter runs only to the end of the loop body.

Of course, since C++ 2014 you can do even better:

for (Author& author: authorList) { doSomethingWith(author); }

but the same rule applies whenever you are attempted to use a while loop with some kind of counter or external position marker.

3.3 Functions should do One ThingThis helps to keep them small, and understandable.

Bad: Suppose a Library class had this:

expand +

Page 126: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public void addBookToCollection (Book book) { List<Author> authors = book.getAuthors(); Title title = book.getTitle(); List<SubjectKeyword> subjects = new List<>(); try { subjects = book.getSubjects(); } catch (SubjectsUnassigned ex) { requestReviewOfSubjects(book); } try { DecimalClassification dewey = oclc.getClassificationCode(book.getISBN()); ShelfLocation intendedLocation = getShelfFor(dewey); book.setLocation (intendedLocation); } catch (OCLCServiceUnavailable ex) { log.error("Error contacting OCLC about " + book.toString(), ex); } try { for (Author author: authors) { authorIndex.add(author, book); } titleIndex.add (title, book); for (SubjectKeyword subject: subjects) { subjectIndex.add(subject, book); } } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } }

It’s long. You might not think this is particularly long, but it’s too long to be expressive.It spans multiple levels of abstraction. Embedded in here are decisions about library structure

how many catalogs exist and what their indexing scheme iswhat classification scheme we use (DeweyDecimal) and who provides that classification service (OCLC).

and about the ADT interfaces used to manipulate the individual catalogs and classification service.

Cleaner:

expand +

Page 127: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public void addBookToCollection (Book book) { addBookToCatalogs(book); moveBookToIntendedLocation(book); } private void addBookToCatalogs(book) { addBookToAuthorCatalog(book); addBookToTitleCatalog(book); addBookToSubjectCatalog(book); } private void addBookToAuthorCatalog(Book book) { List<Author> authors = book.getAuthors(); try { for (Author author: authors) { authorIndex.add(author, book); } } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } private void addBookToTitleCatalog(Book book) { Title title = book.getTitle(); try { titleIndex.add (title, book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } private void addBookToSubjectCatalog (Book book) { try { List<SubjectKeyword> subjects = book.getSubjects(); for (SubjectKeyword subject: subjects) { subjectIndex.add(subject, book); } } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } catch (SubjectsUnassigned ex) { requestReviewOfSubjects(book); } } private void moveBookToIntendedLocation (Book book) { try {

Page 128: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

ShelfLocation intendedLocation = getIntendedLocation(book); book.setLocation (intendedLocation); } catch (OCLCServiceUnavailable ex) { log.error("Error contacting OCLC about " + book.toString(), ex); } } private ShelfLocation getIntendedLocation (Book book) throws OCLCServiceUnavailable { DecimalClassification dewey = oclc.getClassificationCode(book.getISBN()); return getShelfFor(dewey); }

Look, in particular, at the top two functions. * Aren’t they clearly more expressive of what needs to happen? * Is there anything in there that took you out of theLibrary-level of abstraction and forced you to simultaneously think about how more detailed components of the library were designed to work?

3.4 Error Handling is “One Thing”Many of those functions were complicated by the pattern of

1. Try to do something2. Handle the errors can arise if the attempt fails

But those are two different “things”…

expand +

Page 129: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public void addBookToCollection (Book book) { addBookToCatalogs(book); attemptToMoveBookToIntendedLocation(book); } private void addBookToCatalogs(book) { attemptToAddBookToAuthorCatalog(book); attemptToAddBookToTitleCatalog(book); attemptToAddBookToSubjectCatalog(book); } private void attemptToAddBookToAuthorCatalog(Book book) { try { addBookToAuthorCatalog(book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } private void addBookToAuthorCatalog(Book book) { List<Author> authors = book.getAuthors(); for (Author author: authors) { authorIndex.add(author, book); } } private void attemptToAddBookToTitleCatalog(Book book) { try { addBookToTitleCatalog (book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } private void addBookToTitleCatalog(Book book) { Title title = book.getTitle(); titleIndex.add (title, book); } private void attemptToAddBookToSubjectCatalog(Book book) { try { addBookToSubjectCatalog (book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } }

Page 130: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

private void addBookToSubjectCatalog(Book book) throws CatalogingError { List<SubjectKeyword> subjects = getSubjectListOrRequestReview(book); for (SubjectKeyword subject: subjects) { subjectIndex.add(subject, book); } } private List<SubjectKeyword> getSubjectListOrRequestReview(Book book) { try { return book.getSubjects(); } catch (SubjectsUnassigned ex) { requestReviewOfSubjects(book); return new Collections<SubjectKeyWord>.emptyList(); } } private void moveBookToIntendedLocation (Book book) { try { ShelfLocation intendedLocation = getIntendedLocation(book); book.setLocation (intendedLocation); } catch (OCLCServiceUnavailable ex) { log.error("Error contacting OCLC about " + book.toString(), ex); } } private ShelfLocation getIntendedLocation (Book book) throws OCLCServiceUnavailable { DecimalClassification dewey = oclc.getClassificationCode(book.getISBN()); return getShelfFor(dewey); }

We have a lot more functions now, but each one is almost trival to read.

3.5 Avoid DuplicationDuplicated code is code that needs to be fixed/changed multiple times when fixing one bug or adding one feature.

Implicitly couples blocks of code in a way not visible from the interfaces.

Makes it hard to hide (“information hiding”) a design decision.

In our library example, the decision on how to handle cataloging errors has encoded three times:

Page 131: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

private void addBookToCatalogs(book) { attemptToAddBookToAuthorCatalog(book); attemptToAddBookToTitleCatalog(book); attemptToAddBookToSubjectCatalog(book); } private void attemptToAddBookToAuthorCatalog(Book book) { try { addBookToAuthorCatalog(book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } private void attemptToAddBookToTitleCatalog(Book book) { try { addBookToTitleCatalog (book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } private void attemptToAddBookToSubjectCatalog(Book book) { try { addBookToSubjectCatalog (book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } }

Better is to collect that common decision either like this:

private void addBookToCatalogs(book) { attemptToAddBookToAuthorCatalog(book); attemptToAddBookToTitleCatalog(book); attemptToAddBookToSubjectCatalog(book); } private void handleCatalogingError (Book book, CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } private void attemptToAddBookToAuthorCatalog(Book book) { try { addBookToAuthorCatalog(book); } catch (CatalogingError ex) { handleCatalogingError (book, ex);

Page 132: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

} } private void attemptToAddBookToTitleCatalog(Book book) { try { addBookToTitleCatalog (book); } catch (CatalogingError ex) { handleCatalogingError (book, ex); } } private void attemptToAddBookToSubjectCatalog(Book book) { try { addBookToSubjectCatalog (book); } catch (CatalogingError ex) { handleCatalogingError (book, ex); } }

or like this:

private void attemptToAddBookToCatalogs(book) { try { addBookToCatalogs(book); } catch (CatalogingError ex) { log.error ("Error cataloging " + book.toString(), ex); } } private void addBookToCatalogs(book) { addBookToAuthorCatalog(book); addBookToTitleCatalog(book); addBookToSubjectCatalog(book); }

3.6 Distinguish between data structures and “true” objectsSome classes/structs exist purely to specify a data structure, e.g.,

struct AuthorLinkedListNode { Author data; AuthorLinkedListNode* next; AuthorLinkedListNode (const Author& author, AuthorLinkedListNode* nextNode = nullptr)

Page 133: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

: data(author), next(nextNode) {} };

This data type is not intended to be seen outside of Book:

class Book {private: AuthorLinkedListNode* first; AuthorLinkedListNode* last; ⋮ public:

so there’s really little reason to encapsulate its data members.

In some cases we might even enforce that idea

class Book { private: struct AuthorLinkedListNode { Author data; AuthorLinkedListNode* next; AuthorLinkedListNode (const Author& author, AuthorLinkedListNode* nextNode = nullptr) : data(author), next(nextNode) {} }; AuthorLinkedListNode* first; AuthorLinkedListNode* last; ⋮ public:

although this is not always possible.

3.7 The Law of Demeter“Talk to friends, not strangers.”

The law of Demeter: a method f of a class C should only call the methods of:

Page 134: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

C

an object created by fan object passed as an argument to fan object held in a (data structure of a) data member of C

This law is intended to discourage code like this:

class Library { ⋮ void checkOutBookToPatron (Book book, Patron patron) { if (patron.getBranch().getLendingRecord(patron).getNumCheckedOut() < patron.getBranch().getLendingRecord(patron).getCheckOutLimit()) { Date dueDate = Calendar.today().addDays(book.checkOutTerm()); patron.getBranch().getLendingRecord(patron) .addCheckout(book, dueDate); book.checkOutTo(patron, dueDate); } else { throw new CheckoutLimitReached(patron); } }

Some people find the chained calls hard to read.

Perhaps more to the point, this style hides a coupling of this function to the interface of classes LibraryBranch and LendingRecord.

Making the coupling explicit might be an improvement:

class Library { ⋮ void checkOutBookToPatron (Book book, Patron patron) { LibraryBranch patronsHomeBranch = patron.getBranch(); LendingRecord patronLendingRecord = branch.getLendingRecord(patron); if (patronLendingRecord.getNumCheckedOut() < patronLendingRecord.getCheckOutLimit()) { Date dueDate = Calendar.today().addDays(book.checkOutTerm()); patronLendingRecord.addCheckout(book, dueDate); book.checkOutTo(patron, duedate); } else { throw new CheckoutLimitReached(patron); } }

Page 135: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

but it doesn’t make the coupling go away.

The highlighted calls violate the Law of DemeterLook at the other calls. Do you see why they don’t violate that law?

If anything, it makes it clearer that we are not sticking to a uniform level of abstraction here. So, better still:

class Library { ⋮ void checkOutBookToPatron (Book book, Patron patron) { if (patron.canCheckOutMoreBooks()) { Date dueDate = Calendar.today().addDays(book.checkOutTerm()); patron.addBookToCheckedOutList(book, dueDate); book.checkOutTo(patron, duedate); } else { throw new CheckoutLimitReached(patron); } } class Patron { ⋮ public void addBookToCheckedOutList (Book book, Date dueDate) { LibraryBranch patronsHomeBranch = branch; LendingRecord patronLendingRecord = branch.getLendingRecord(patron); patronLendingRecord.addCheckout(book, dueDate); } public boolean canCheckOutMoreBooks() { LibraryBranch patronsHomeBranch = branch;; LendingRecord patronLendingRecord = branch.getLendingRecord(patron); return patronLendingRecord.getNumCheckedOut() < patronLendingRecord.getCheckOutLimit() }

which still has multiple violations, so we need to keep going:

class Patron { ⋮ public void addBookToCheckedOutList (Book book, Date dueDate) { LibraryBranch patronsHomeBranch = branch; branch.addBookToCheckedOutList(patron, book, dueDate); }

Page 136: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public boolean canCheckOutMoreBooks() { LibraryBranch patronsHomeBranch = branch;; return branch.getNumCheckedOut(patron) < branch.getCheckOutLimit(patron); } class LibraryBranch { ⋮ public void addBookToCheckedOutList (Patron patron, Book book, Date dueDate) { LendingRecord patronLendingRecord = lendingRecords.get(patron); patronLendingRecord.addCheckout(book, dueDate); } public boolean canCheckOutMoreBooks() { LendingRecord patronLendingRecord = lendingRecords.get(patron); return patronLendingRecord.getNumCheckedOut() < patronLendingRecord.getCheckOutLimit(); }

Apply this “law” with caution.Personally, I like the 2nd version better.Martin also argues against functions taking more than one or two parameters, but this kind of refactoring for Demeter can result in longer parameterlists.

3.8 Error HandlingFavor exceptions rather than special return codes, returning null, etc.Martin argues for unchecked exceptions rather than checked to avoid percolating throws declarations (and their accompanying coupling) throughout thecode.

3.9 Classes should be small!Martin argues strongly against large classes.

I.e., the number of responsibilities should be small.

Roughly speaking, “responsibilities” are measured in terms of public members.

get/set pairs probably count as only one.

But refactoring to accomodate some of his other recommendations (e.g., “functions should do one thing”) tends to make the number of function membersexplode.

Page 137: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The trick is that the added members are generally private, not public.

Cohesion

When is the list of public members too big?When you cannot assign a simple overall description of what they all do in the class.

The class is not cohesive if its public members perform wildly different tasks.The Single Responsibility Principle (SRP, part of SOLID) states that every class should have one overall responsibility.

Martin: We should also be able to write a brief description of the class in about 25 words, without using the words “if,” “and,” “or,” or “but.”

1: This practice is not commonly included in writing about Clean Coding, but I think that’s because it is generally taken for granted that “every” programmerdoes this. But I see lots of violations of this practice in student coding every semester. – SJZ

Page 138: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Integrated Development EnvironmentsSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 The Components of an IDE2 IDE Examples

2.1 emacs2.2 Microsoft Visual2.3 NetBeans2.4 Single-Language IDEs

3 Eclipse3.1 Availability

Abstract

Integrated Develop Environments (IDEs) are software packages that attempt to provide comprehensive support for coding, testing, and debugging

and possible other software construction activities

In this lesson we discuss the minimum expectations we have for an IDE. We also look at some of the optional but desirable features we would like to see.

We will survey some common popular IDEs and comment briefly on the features they provide, before settling down upon Eclipse, the IDE that will be usedthroughout the remainder of this course.

1 The Components of an IDEWhat’s the minimum that we expect in an IDE?

editor

build support

maybe no more than compiler & linkerinvocationwith error messages captured/interpreted/walked by editor

run/execute programs

Page 139: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

debugger

The Components of an IDE (optional)

What would we like to see in an IDE?

syntax highlighting & aid in editor

Do we need to wait until we actually run the compiler to be notified of simple mistakes?

documentation (API) look-upe.g., I know this variable m is a pointer to a std::map<int,string>, so what can I write after “m->”?

flexible/configurable build supportWhat if our project uses multiple programming languages?What if we have a program that generates part of the source code and so needs to be run before we start compiling?

packaging/deployment options

preparing zip, jar, and war archivespackaging code as a static or dynamic libraryposting compiled code to an online repository

The Components of an IDE (deluxe)

What makes us positively giddy when we see it in an IDE?

smart feedback in the editorlearns API of code we wrote

e.g., I know this variable p is a pointer to a MyOwnADT, so what can I write after “p->”?suggestions

coding aids in editortemplatescommon refactoring (transformations)

documentation generationtest integrationintegration with version control

2 IDE Examples

Page 140: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.1 emacsThe *nix swiss army knife of editors, emacs has long functioned as a basic IDE:

syntax-highlighting editorbuild support (invokes *nix make)

parses error messages from compilers & other toolsdebugger interfaceworks directly with many version control systems

References, if you are unfamiliar with this:

Compiling in emacsemacs Debugging mode (CS252)

2.1.1 emacs Strengths and Weaknesses

highly portablesupports virtually any language you would have a compiler foreven in windowed mode, leans toward keyboard rather than mouse

(Not sure if that’s a pro or a con – personally I hate having to lift my hand from the keyboard to reach for my mouse every few seconds. YMMV.)outdated interface

I’m just waiting to see, some day, some Linux IDE come out that announces a “retro” emacs-style skin.

high learning curve

2.2 Microsoft VisualVisual Studio

syntax-highlighting editorbackground compilation provides quick feedback on simple errors

built-in build managerlimited configurability

debugger interfacesome designer tools (e.g., design classes in UML)

2.2.1 Visual Strengths and Weaknesses

Page 141: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

wide variety of languages (but Microsoft processors)single-OSclosely integrated with Microsoft compilersmodern, mouse-oriented interface

I’ve never been fond of Visual, but that comes more from my opinion of the MS compilers. MS C++ had recurring issues with basic standards conformance andstd library implementation. And MS’s support of Java was perpetually luke-warm.

2.3 NetBeansFree IDE originally distributed by Sun as “the” development platform for Java.

Still largely Java centric, though some support for other languagesparticularly web-related languages like Javascript, CSS, XSL

Portable (written in Java)Tends to track the trends and hot topics in the Java world promptlyeditor, build manager, debuggermoderately extensible

Netbeans and Visual clearly stole interface ideas from one another.

(Then Eclipse came along and stole from them both. Nowadays it’s pretty clear that they are all very much aware of anything resembling an innovation by oneof the others.)

I have not used NetBeans in a long time. I remember it as being incredibly sluggish even on reasonably high-powered desktops.

My enduring impression is that Eclipse seemed to do everything NetBeans wanted to do, did it about 6 months later, but did it better.

2.4 Single-Language IDEsThe open source community has produced numerous single-language IDEs.

Many are focused on educational use.

Examples:

C++Bloodshed Dev-C++, Code::Blocks

JavaBlueJ, Dr. Java, jGrasp

Page 142: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3 EclipseProbably the hottest IDE in the open source world:

syntax-highlighting editor, multi-language supportstrong hinting based on both standard and user-written APIs, interface aidtemplates and refactoring

build supporteasily configured or switched to other build tools

background compilation for quick detection of language errorsintegrated *unit testing supportsolid debugger, intuitive handling of threadssome packaging & deployment supportintegrates with most version control systemsmodular plug-in extensibility with a rich variety available

Eclipse is available here.

3.1 AvailabilityEclipse is installed on both the CS Dept Windows PCs and Linux servers

Includes basic packages for Java & C++ support

We will be working with much more advanced tools in this course.

You will need to install your own plugins.

Every student will therefore need to prepare their own personal development environment with

Java 1.8g++Eclipse

This will be discussed in more detail in an upcoming assignment. .

Page 143: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

User StoriesSteven J Zeil:

Last modified: Dec 21, 2019

Contents:1 User stories

1.1 Writing User Stories1.2 Characteristics of good stories1.3 Example (Spreadsheet)1.4 Special Stories

2 Organizing Constructions via Stories2.1 Planning an Increment

3 Stories become Tasks3.1 Tasking Example 13.2 Task Boards3.3 The Definition of Done3.4 Tasking Example 2 (Spreadsheet)

4 Thinking Incrementally4.1 Vertical Thinking

Abstract

User stories are used in incremental SDPMs as a way of organizing work during software construction.

A user story is a simple description of desired functionality, often written as a single sentence on an ordinary index card.

Over time, user stories are modified by

adding an estimated effort to implement that story.adding priority info indicating how important this story is to the end users.splitting stories that are too big to be implemented during a single pass of an incremental processmerging related stories that have become too detailed to implement separately.

In an incremental construction process, small sets of stories are chosen for an upcoming increment as the target for the next round of construction.

1 User stories

Page 144: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Key idea in all agile variations.

A user story is

a mechanism for incremental requirements elicitation and analysis.a way of organizing and tracking work during iterative development

1.1 Writing User StoriesOne or two-line description of work to be done

Usually written on index cardsOften posted on a bulletin board in team workspaces

Each story describes something of value to a customere.g., “Complete the integration tests” is not a story.

Stories have clear completion criteria.

They must be validatable.

1.1.1 Examples of User Stories

As a calendar owner, I want to view my schedule for the coming week.

As a visitor, I want to see when a calendar owner has free time in their schedule.

As a calendar owner, I want to receive email notication when someone accepts a proposed appointment.

As a systems administrator, I want to back up all calendars so that the data is safeguarded.

These illustrate some common patterns:

“As a {role}, I want {goal/desire}”“As a {role}, I want {goal/desire} so that {benefit}”

1.1.2 Stories are not Requirements

…despite the focus on functionality and non-functional characteristics.

Stories are “a promissory note for a future conversation” (Cockburn)A use-case is a transcript of that conversation (Standley)

Page 145: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Stories are a way of prioritizing workIncluding the work of eliciting detailed requirements

1.2 Characteristics of good stories

1.2.1 Customer centric

Stories should express a customer’s point of view, using the customer’s language.

What is the value of this story to the customer?Which customers is this story important to, and how does it affect them?

One way to achieve this is to ask the customers to write the stories.

Stories should be rated by customer priority

1.2.2 Estimatable

At some point in the process, we must add estimates to our stories indicating how much time we think it will take to complete them. Such estimates aid us infuture scheduling. We want to select, for each upcoming increment, enough stories to add a substantial amount of functionality, but not so many that we will beunable to complete them in the time allotted for that increment.

The estimates are commonly not written in hours, person-days or other real time units, at least not unless your team is actually experienced enough to do a goodjob at coming up with such numbers. Instead, a groups of “typical effort” stories is selected as defining unit 1.0 difficulty, and the others are expresssed innumbers relative to that, e.g., “I think this will take half again as long as the typical stories, so I will estimate it at 1.5.”

The team must estimate the effort required to implementation a story.

Often done on a relative scale.

“This story will take half again as much time as our average story.”

Big, complicated stories are harder to estimate

Split them into smaller stories

1.2.3 Validatable

Good stories have completion criteria that can be validated.

It’s important to know when we are done implementing a story.

Page 146: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Agile generally recognizes stories as only 0% or 100% completed – no fractions.

Definition of Done: team’s agreed-upon criteria for declaring work done (e.g., tests passed, integrated, documented, …)

A common saying among agile teams:

“I know that you are done, but are you DONE-done?”

Non-functional stories

Stories can describe new functionality or improvements to existing functionality:

Performance requirements,ScalabilityPortability

May be harder to define precise completion criteria.

1.2.4 Some Examples of “Bad” Stories

Automate integration build

no customer value

Improve performance

no completion criteria

Implement interfaces between subsystems

too big – cannot be accomplished by 1/2 people in a short period of timehas “obvious” decompositions (separate interfaces between each pair of subsystems) that would make it more suitable

1.3 Example (Spreadsheet)

Page 147: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Look at these stories

1.4 Special StoriesThe traditional user story is customer-centric.

But sometimes there are units of work required that don’t fit the traditional definition.

1.4.1 Documentation stories

Agile places less emphasis on documentationMost (e.g., API documentation) is just factored in as part of the effort of implementing a normal storyOccasionally, special documentation needs arise

user manuals, certification requirements

1.4.2 Bug Stories

Fixes for bugs that evaded your unit testsCan be hard to estimate effortallocate fixed time, then schedule a “sequel” story

1.4.3 Spike Stories

Can’t estimate some stories because of lack of informationSpike stories say “Research how to estimate story X”.Name comes from practice of spike solutions, simple throw-away prototypes or experiments

2 Organizing Constructions via StoriesRemember that each increment is supposed to yield a runnable program that implements some addition functionality not present in earlier increments.

Something that we can actually show to a manager/customer/user

Stories also add functionality, but an individual story might not yield something visible while running the program.

2.1 Planning an IncrementIn planning our next increment or release, we select a set of stories to be implemented during our next development interval.

Page 148: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Together, they should add up to a visible addition of functionality to the working system.

Use the estimates attached to each story to scale the amount of work planned for this development interval to a reasonable size.

Early in a project, we might need to guess just how much time it will take to 1 estimated unit of effort.

This should become clearer as we move forward through the project.

2.1.1 Posting Stories

There are a variety of ways to visually organize stories to enhance planning and to give visual evidence of the progress being made.

Page 149: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Stories grouped on a story board to help “enrich” the stories

Story boards can be organized in many different ways

2.1.2 Backlogs

A term used in conjunction with story-based planning is “backlog”.

In normal English usage, “backlog” sounds negative: You have a backlog because you are “backed up” – your progress has been too slow.

In incremental development, there is no such negative connotation.

Page 150: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The project backlog is a list of unimplemented:

Stories, orRequirements for which stories have not been written.

3 Stories become TasksWhen we pick up a story for development there may be many steps required to actually complete it.

Typically we indicate this by listing (often on the same card as the story) the required tasks.We then track the completion status of individual tasks.

It’s possible that a developer will do some tasks on one story, then move to tasks of a second story, then return to the first, etc.

3.1 Tasking Example 1In the spreadsheet stories, I suggested that the stories for the first increment might be

As a calculation author I would like to load a spreadsheet via the CLI.As a calculation author I would like to generate a value report via the CLI.As an API user I would like to create a new spreadsheet.As an API user I would like to load a spreadsheet from a file containing only simple assignments.As an API user I would like to add a numeric literal to a cell in a spreadsheet.As an API user I would like to obtain the value of a cell whose formula contains only literals.

Of these, I would likely pick

As an API user I would like to create a new spreadsheet.

to start.

Then, I would break it into tasks, some of which would be necessitated by this being the first story developed in a project:

1. Set up project repository

2. Set up directories and initial build file.

Page 151: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3. Design initial spreadsheet API.

4. Write unit test for spreadsheet creation via that API.

5. Implement the spreadsheet creation function.

6. Commit implementation to the repository.

Some comments about these tasks:

The italicized items are all concepts that we will tackle in a subsequent lesson.

The sequence defined by items 3-4-5 is characteristic of Test-Driven Development:

We always write a test that will initially fail (if it can be run at all) before doing the implementation.That way we

know when we have succeeded with our implementation.already have a test driver ready the moment we have written part of the actual code.

Although, eventually, we will have an entire test for the spreadsheet API, we don’t try to do that all at once. The tests are written incrementally, justlike the application itself.

3.2 Task BoardsTask boards show the completed and in-progress stories for the current increment:

On this board, the stories are in the cards on the left.The post-it notes represent tasks, and are moved to the right as progress is made.

The post-its often have the name(s) of the developers that have taken on each task.

The “To do” column is sometimes labeled the “sprint backlog”

This is the collection of not-completed tasks scheduled for the current increment.The name comes from the Scrum agile process model, where a period of development for one increment is called a “sprint”.

Page 152: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.3 The Definition of Done

"I know you say that you are done. But are you done done? – apocryphal question from one team member to another.

The definition of done is a set of criteria that must be met before a development team agrees that a story has been completed and that the people assigned to itare ready to move on to tackle something else.

Page 153: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Typically, this definition is established by the team at the start of the project.

Typical Criteria in a Definition of Done

Code passes all unit tests.System level (functional) tests have been created/passed.Code is checked in and shared with the rest of the team.Code has been integrated and is used by other code in the project.Code meets documentation standards.Code has been reviewed by other team members and found free of major problems.Code has been reviews by analysis tools and found free of major problems.

3.3.1 Tasks can Follow the Definition of Done

A common recommendation for division of a story into tasks is to turn each criterion chosen for the teams’ DoD into a task.

3.4 Tasking Example 2 (Spreadsheet)

Page 154: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

I consult my task board and decide that I will next work on the story toimplement a sqrt operator.

My project “definition of done” says that I must have

coded the story (includes writing nad passing unit tests)created a system testintegrated the new code

so I would expect to divide this into at least three tasks.

Page 155: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

As it happens, I know that there are two nearly independent coding issuesinvolved:

1. I need to add a new “square root operator” class that captures the idea ofevaluating a square root and the output of expressions involving squareroots.

2. I need to modify the expression parser so that it recognizes expressions ofthe form “sqrt(…)”.

Those are independent enough that I choose to split them.

So I start adding tasks to the swim lane for my chosen story:

Page 156: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

until I have my DoD criteria covered:

Page 157: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

When I am actually ready to start work, I assign one of the “code” tasks tomyself and move it into the “In progress” column.

4 Thinking IncrementallyTo me, one of the challenges in designing good stories and in scheduling them is to envision possible increments.

When a large portion of the implementation is done, this is relatively easy.

Just list the missing features. Adding a feature (or two, or three) is a “natural” increment.

But what about when you have nothing at all working yet?

It can feel like you need to get a massive amount implemented before anything works at all!

4.1 Vertical Thinking

Page 158: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Partly, I think this is awkward because there’s a mis-match between how we design and think about codeand how we schedule increments.

We design code in “horizontal” layers of abstraction.

Page 159: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

But an increment is a “vertical slice” of functioning code.

Page 160: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4.1.1 Iterative Means We Can Come Back

Incremental development is also iterative – we can revisit components in later iterations.

Sometimes that’s easy.

It’s usually pretty easy to implement part of a menu or toolbar.Part of a window is usually easy too

Sometimes it’s not

Think of a typical ADT - how can you implement part of it?

4.1.2 Faking It

Page 161: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

If we need to implement part of a complicated ADT during an increment…

Choose a quick (to implement) data structure now, with the intention of replacing it later when we need more of the ADT API to work.

Or, take a lesson from integration testing

Create stubs for unimplemented lower-layer components.Carried to an extreme, you can be pnambic

Page 162: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Verification and ValidationSteven Zeil

Last modified: Dec 21, 2019

Contents:1 The Process2 Non-Testing V&V

2.1 Code Review2.2 Mathematically-based verification2.3 Static analysis tools2.4 Cleanroom software development

Abstract

Verification & Validation: any activities that seek to assure that a software system meets the users’ needs.

The principle objectives are

the discovery of defects in a system, and

the assessment of whether or not the system is usable in an operational situation.

The most familiar form of V&V is testing.

Through the rest of this module, we will indeed be taking a close look at testing, unit testing in particular. Before doing that, however, it’s worth noting thattesting is not the only way to do V&V.

We will look at various forms of

code review and inspection,proof, andstatic analysis

as alternatives or, more often, supplements to testing.

1 The Process

Page 163: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Verification & Validation

Verification:

“Are we building the product right”The software should conform to its (most recent) specification

Validation:

“Are we building the right product”The software should do what the user really requires

Testing

Testing is the act of executing a program with selected data to uncover bugs.

As opposed to debugging, which is the process of finding the faulty code responsible for failed tests.

Testing is the most common, but not the only form of V&V

What Can We Find?

Fault: A defect in the source code.

Failure: An incorrect behavior or result.

Error: A mistake by the programmer, designer, etc., that led to the the fault.

Industry figures of 1-3 faults per 100 statements are quite common.

2 Non-Testing V&V

Static Verification

Verifying the conformance of a software system and its specification without executing the code

Involves analyses of source text by humans or software

Page 164: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Can be carried out on ANY documents produced as part of the software process

Discovers errors early in the software process

Usually more cost-effective than testing for defect detection at the unit and module level

Allows defect detection to be combined with other quality checks

Static verification effectiveness

It has been claimed that

More than 60% of program errors can be detected by informal program inspections

More than 90% of program errors may be detectable using more rigorous mathematical program verification

The error detection process is not confused by the %existence of previous errors

2.1 Code ReviewInspecting the code in an effort to detect errors

Desk Checking

Inspection

2.1.1 Desk Checking

An exercise conducted by the individual programmer.

“Playing computer” with the aid of a listing.

Values of variables are tracked using pencil and paper as the programmer moves step-by-step through the code.

Can be done with pseudocode, diagrams, etc. even before code has been written

A good way to find fundamental flaws in algorithms, especially before actually writing the code.

Useful in checking the results of an intended change during debugging.

2.1.2 Inspection

Page 165: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Formalized approach to document reviews

Intended explicitly for defect detection (not correction)

Defects may be logical errors, anomalies in the code that might indicate an erroneous condition (e.g. an uninitialized variable) or non-compliance withstandards

Inspection pre-conditions

A precise specification must be available.

Team members must be familiar with the organization standards.

Syntactically correct code must be available.

An error checklist should be prepared.

Management must accept that inspection will increase costs early in the software process.

Management must not use inspections for staff appraisal.

Inspection procedure

1. System overview presented to inspection team

Code and associated documents are distributed to inspection team in advance

Inspection takes place and discovered errors are noted

After inspection meeting,

Modifications are made to repair discovered errorsRe-inspection may or may not be required

Inspection teams

Made up of at least 4 membersAuthor of the code being inspectedReader who reads the code to the teamModerator who chairs the meeting and notes discovered errors

Sometimes a separate “secretary” / “scribe” is used

Page 166: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Inspector(s) who finds errors, omissions and inconsistencies

Inspection rate

500 statements/hour during overview125 source statement/hour during individual preparation90-125 statements/hour can be inspectedInspection is therefore an expensive processInspecting 500 lines costs about 40 man/hours effort ( per line)

Inspection checklists

Checklist of common errors should be used to drive the inspection

Error checklist is programming language dependent

The “weaker” the type checking, the larger the checklist

Examples: Initialization, Constant naming, loop termination, array bounds, etc.

Inspection checks

What kinds of faults would appear in a checklist?

Data Faults

Are all variables initialized before use?Have all constants been named?Should array lower bounds be 0, 1, or something else?Should array upper bounds be size of the array or size ?If character strings are used, is a delimited explicitly.Are all data members initialized in every constructor?Is C++’s “Rule of the Big 3” satisfied?

Control Faults

For each conditional statement, is the condition correct?Is each loop certain to terminate?Are compound statements correctly bracketed?In case statements, are all possible cases accounted for?

≥ $8

−1

Page 167: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

I/O Faults

Are all input variables used?Are all output variables assigned before being output?

Interface faults

Do all function/procedure calls have the correct number of parameters?Do the formal and actual parameter types match?Are the parameters in the right order?If components access shared memory, do they have the same model of the shared memory structure?

Storage Mgmt Faults

If a linked structure is modified, have all links been correctly assigned?If dynamic storage is used, has space been allocated correctly?Is space explicitly deallocated after it is no longer required?Are all pointer data members deallocated in the destructor?

Exception Mgmt Faults

Have all possible error conditions been taken into account?

Stylistic/standards Faults

Are names understandable?Does code conform to standards for commenting?Does code provide capturable outputs for testing?Does code take advantage of possible re-use?

2.2 Mathematically-based verificationVerification is based on mathematical arguments which demonstrate that a program is consistent with its specification

Programming language semantics must be formally defined

The program must be formally specified

Program proving

Rigorous mathematical proofs that a program meets its specification are long and difficult to produce

Page 168: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Some programs cannot be proved because they use constructs such as interrupts.

These may be necessary for real-time performance

The cost of developing a program proof is so high that it is not practical to use this technique in the vast majority of software projects

Program verification arguments

Less formal, mathematical arguments can increase confidence in a program’s conformance to its specification

Must demonstrate that a program conforms to its specification

Must demonstrate that a program will terminate

Model Checking

Simplified models on which properties can be proved

FSAMarkov Chains

Focus on properties short of correctness

e.g., avoiding race conditions

Machine-Assisted

2.3 Static analysis toolsSoftware tools for source text processing

Try to discover potentially erroneous conditions in a program and bring these to the attention of the V & V team

Very effective as an aid to inspections. A supplement to but not a replacement for inspections

Static analysis checks

What kinds of faults can be detected by static analysis?

Data faults

Page 169: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Variables used before initializationVariables declared but never usedVariables assigned twice but never used between assignmentsPossible array bounds violationsUndeclared variables

Control faults

Unreachable codeUnconditional branches into loops

Interface faults

Parameter type mismatchesParameter number mismatchesFunction return values unusedUncalled functions and procedures

Storage mgmt faults

Unassigned pointersPointer arithmetic

Stages of static analysis

Control flow analysis.

Checks for loops with multiple exit or entry points, finds unreachable code, etc.

Data use analysis.

Detects uninitialized variables, variables written twice without an intervening assignment, variables which are declared but never used, etc.

Interface analysis.

Checks the consistency of routine and procedure declarations and their use

Information flow analysis.

Identifies the dependencies of output variables. Does not detect anomalies itself but highlights information for code inspection or review

Path analysis.

Page 170: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Identifies paths through the program and sets out the statements executed in that path. Again, potentially useful in the review process

These stages generate vast amounts of information.

Must be used with care.

2.4 Cleanroom software developmentThe name is derived from the ‘Cleanroom’ process in semiconductor fabrication. The philosophy is defect avoidance rather than defect removal.

Software development process based on:Incremental developmentFormal specification.Static verification using correctness argumentsStatistical testing to determine program reliability.

Testing is actually forbidden!Code generation is suppressed.Compilers used for syntax/semantic checking only.

Cleanroom process teams

Specification team.

Responsible for developing and maintaining the system specification

Development team.

Responsible for developing and verifying the software. The software is NOT executed during this process

Certification team.

Responsible for developing a set of statistical tests to exercise the software after development.

Reliability growth models used to determine when reliability is acceptable

Results in IBM have been very impressive with few discovered faults in delivered systems

Some independent assessment shows that the process is no more expensive than other approaches

Page 171: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

But no controlled studiesAnd their assessment of other approaches is questionable

Fewer errors than in a ‘traditional’ development process

Not clear how this approach can be transferred to an environment with less skilled or less highly motivated engineers

Page 172: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Lab - EclipseSteven Zeil

Last modified: Dec 21, 2019

This lab will give you the opportunity to explore some of the kinds of problems that static analysis tools can help you with. This will be a fairly basic exercise.We won’t be installing any new tools for this lab – just making some better use of an already familiar tool, the g++ compiler.

We will look at some more advanced tools later in the sememster.

1 Starting1. Set up a C++ project to use in this lab. You can use any IDE, though if you have been working through the earlier assignment on Eclipse, it would

probably make the most sense to use that. But you can use Code::Blocks or even emacs. You are going to be doing a lot of stepping though errormessages and examining the associated code, so pick somethings that does that job well.

Your C++ code for this project should be reasonably complicated. It should involve multiple .cpp files and some use of classes. It might even besomething that you never got working correctly, though it should compile.

2. Build (compile) your project in the normal fashion. Most IDEs will display somewhere the compilation commands that they are running on your behalf.Take note of these. (In Eclipse, you can find these in the Console tab of the bottom central window.)

Also take note of any compiler warnings that were issued. (Presumably you did not get actual errors that owuld have prevented compilation.) Stepthrough these warnings and take note of the kind of things the compiler is bringing to your attention.

3. At the end of this exercise summarize your results on the discussion board.

2 -WallThe -Wall flag, added to a g++ compilation, causes the compiler to emit warnings for a number of practices that, in the opinion of the g++ designers, are bothquestionable and easily avoided.

Some of the things checked by -Wall include

out of bound accesses to arrays, when compiled with -O2

Page 173: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

use of C++11 features when the explicit option for these has not been supplieduse of char in array subscriptsabuse of enumeration types in comparisonsbad formats in printfpossibly uninitialized variables

You can find the full list here, which is best read with a separate browser window open to this index.

1. If your project build does not already include -Wall, add it to the compiler options. (See Changing Compiler Options below.)

Rebuild your project. (You may need to clean/clear the project first to force a full rebuild, because you have not actually touched any of the source code.)

2. If your project build already included -Wall, try removing it and rebuilding. Any changes?

3. Walk through the messages now. Do you see any changes? If not, try adding one of the problems described earlier as being under the purview of -Walland rebuild again.

Take particular note of any messages that indicate a true potential problem with your code. Take note also of nay false alarms, things that you know areOK even though they were flagged. (Keep your mind open, at least, to the possibility that there may be potential problems that you aren’t aware of.)

4. Any surprises? Discover any hidden problems? Or, maybe, just find some of the warnings you got to be inexplicable? Post about your experiences in theHallway Forum.

3 -Wextra-Wextra adds still more checks, including warning for empty loop and if bodies, comparisons between signed and unsigned integers, and parameters tofunctions that are never used in the function body.

1. Repeat the process from -Wall, this time adding -Wextra in addition to -Wall.

4 -Weffc++Weffc++ adds warnigns for a number of issues from Scott Meyers’ Effective C++ and More Effective C++.

These include warnings if you fail to implement your own version of the copy constructor and assignment operator for classes that have dynamic allocation.(You should recall discussions of the C++ Rule of the Big 3 from your earlier courses.) Also flagged are operator= implementations that fail to return *this,and the use of assignment rather than initialization within constructors.

Page 174: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. Repeat the process from -Wall, this time adding -Weffc++ in addition to -Wall.

5 Closing ThoughtsThese options can give you early warning of potential problems, but only if you actually read and consider the warning messages. The struggle with most staticanalysis regimens is to balance the value of the legitimate warnings against the annoyance of wading through many false alarms.

6 Appendix: Changing Compiler OptionsRead on if you are not familiar with the process of changing the options used to compile C++ code in your favorite IDE.

6.1 emacs/makeIf you are using emacs as your IDE, you are probably using a make file to control your build.

Look in the make file for the actual g++ commands and add the desired option there.

It’s a common style among writers of make files to invoke the compiler via a variable name, usually “CXX”, e.g.,

CXX=g++ ⋮ $(CXX) -o $@ -c $*.cpp

The reason is that this make file can then easily be modified to use a different compiler by changing that variable. In fact, it can be changed directly fromthe command line. For example, if I wanted to generate a Windows executable when running the compiler on a Linux box, I say

make -DCXX=CXX=x86_64-w64-mingw32-g++

to use a Windows cross-compiler instead of the normal g++.

It’s also common to package the compilation options in a variable. For example, I often use CPPFLAGS, in conjunction with a rule like:

CXX=g++ CPPFLAGS=-g -std=c++11 %.o: %.cpp $(CXX) $(CPPFLAGS) -MMD -o $@ -c $*.cpp

Page 175: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

So any change to the CPPFLAGS variable would update all compilations generated by this make file.

6.2 EclipseTo change C++ compilation options in Eclipse, much depends on whether you are using the Eclipse build-in project manager or a separate make file to controlthe build. If you are using a make file, then follow the instructions given above.

If you are working with the built-in manager, go to the Project menu and select Properties, `C/C++ Build“, ”Settings“, then the ”Tool Settings“ tab. You canthen select the option flags you want directly in the ”GCC C++ Compiler“ ”Warnings“ or ”Miscellaneous“ area. Note that when you select an option in one ofthese areas, then it gets added to the summary ”All options“ at the ”GCC C++ Compiler" area.

6.3 Code::BlocksFrom the Project menu, select Build Options, then Compiler Settings. You can then try to select your desired option form the description in CompilerFlags or type it in directly under Other options.

Page 176: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

TestingSteven Zeil

Last modified: Dec 21, 2019

Contents:1 The Testing Process

1.1 The Steps in a Testing Process2 Stages of Testing3 Unit Testing

3.1 Scaffolding4 Integration Testing

Abstract

Testing is a critical skill for any software developer, but its treatment in most textbooks belies the complexity of this process.

We review the component activities that go into testing code, from the design of testcases to the invocation of the testing oracle to judge correctness of the output.

We will then examine the ways in which testing fits within a process model, looking at unit testing, integration testing, system testing, acceptance testing, andregression testing.

Page 177: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1 The Testing Process

The diagram here illustrates the steps involved in testing code.

Although you have been doing testing for some time as CS students, most of yourtesting has probably been informal. Still most of the activities here should be familiarto you.

Beginning from an overall test plan (or test specification),

we eventually seek to discover a collection of failures

These failures become the input to the process of debugging, where weseek to find the faults in the code responsible for those failures.

Terminology

Failure: An execution on which incorrect behavior occurs

Fault: A defect in the code that (may) cause a failure

Related to these, though not part of our testing process:

Page 178: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Error: A human mistake that results in a fault, or,

alternatively, the difference between the expected output and the actual output on a failed test.

These terms get abused a lot, but there really is a clear difference among the three.

In informal discussions, we sometimes like to make reference to something that is wrong even if we aren’t quite sure (or just don’t care) whether it is an error, afailure or a fault. I tend to use the words like “bug” or “problem”, or “defect” in those circumstances, as these do not have formal definitions.

1.1 The Steps in a Testing Process

A test plan (more properly, a test specification) describes a set of test cases.

Test case: a general description of a required test

For any given test case, there may be many possible inputs that would serve. Forexample, in testing a square root function, we might have a test case “find asquare root where the value cannot be represented exactly in floating point”, forwhich possible inputs would be 2.0, 3.0, 200.0, etc.

With that in mind, the first step in testing is to

1. Derive inputs for each test case.

In most cases, you will also need to record the expected outputs or behavior foryour test inputs.

The inputs and expected outputs may be recorded in a database of regression tests for later. But the most obvious use for the new inputs is to…

2. Execute the tests

The test inputs are fed into the program being tested and the actual outputs collected.

3. Determine which tests have failed.

The test inputs, actual outputs obtained from their execution, and the expected outputs are passed on to the testing oracle. The oracle is the person,program, or process used to determine if a test has failed.

4. Pass the failures on for debugging.

The purpose of debugging is to determine the faults i nthe code that are actually responsible for the failures observed during testing.

Page 179: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1.1.1 Oracles

The testing oracle is the person, program, or process used to determine if a test has failed.

The term “oracle” stems from the “Oracle of Delphi”, a priestess of Apollo in ancient Greece who was believed to have the gift of divination, although herpronouncements were famously cryptic. In Computer Science, “oracles” are invoked as models for answering questions that cannot be entirely solved byalgorithms.

Testing oracles come in many forms, ranging from automated oracles that we will consider in a later lesson, to the “eyeball oracle” that you probably employfor most of your academic assignments.

The eyeball oracle is notoriously prone to missing failures. We just aren’t very good at looking at thousands of lines of output and picking out the one or twothat are incorrect. On the other hand, the eyeball oracle is very good at noticing faults from the early stages of requirements and design that were faithfullytranslated into code (i.e., the eyeball oracle does more validation than verification.

Another common form of oracle is the “head to head” oracle. If we are developing a system to replace an existing one, then we can run the test inputs throughboth systems and compare them, usually by simple byte-by-bye comparison (e.g., the diff command).

This sort of situation (head to head testing) is more common than you might think. Developing new, first-time systems from scratch is a comparatively rareactivity. Even if we expect to add some new functions to the new system (or are adding functionality to the existing one), we can use head-to-head for theshared portion of the two.

1.1.2 Regression

The regression log or regression database is a collection of tests and expected outputs from past testing.

It is used, during regression testing, to quickly rerun old tests. Regression databases can quickly grow to thousands or tens of thousands of cases or more. Itbecomes particularly important that we not rely on the eyeball oracle for evaluating regression tests.

2 Stages of TestingWe recognize several different stages of testing. These differ in scope (how much of the program is involved) and purpose (who conducts the testing and whatinformation do they derive from it).

Unit Test: Tests of individual subroutines and modules,

usually conducted by the programmer.

Integration Test: Tests of “subtrees” of the total project hierarchy chart (groups of subroutines calling each other).

generally a team responsibility.

Page 180: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

System Test: Test of the entire system,

supervised by team leaders or by V&V specialists.Many companies have independent teams for this purpose.

Regression Test: Unit/Integration/System tests that are repeated after a change has been made to the code.

Acceptance Test: A test conducted by the customers or their representatives to decide whether to purchase/accept a developed system.

Testing goals

Focusing on the differing purposes of testing, …

Unit Test: does it work?

Integration Test: does it work?

System Test: does it work?

Regression Test: has it changed?

Acceptance Test: should we pay for it?

Regression testing is particularly interesting. We regression test after a change to make sure we have not inadvertently broken anything else. In fact, we reallyare looking for unintended effects of our changes.

Regression logs commonly record tests that have been both passed and failed, and we want to be informed of changes in that status.

So, while most testing has possible outcomes “pass” or “fail”, regression testing has outcomes

Expected pass: this test used to pass, and it still doesExpected fail: this test used to fail, and it still doesUnexpected pass: this test used to fail, and but not it passes

This can be a concern because, if we did not intend to fix that failure with our most recent changes, it suggests that we now have a fault somewherein the code that is now hidden — we no longer have a test case revealing the fault, so it’s lurking in there somewhere, just waiting to spring out atsome particularly inopportune time.

Unexpected fail: this test used to pass, and now it fails.

Sadly, very common. This means that while fixing one bug, we broke something else.

Page 181: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3 Unit TestingWe’re going to spend a lot of time taking about unit testing this semester, so it deserves some special attention now.

By testing modules in isolation from the rest of the system

Easier to design and run extensive tests

Much easier to debug any failures

Errors caught much earlier

Main challenge is how to test in isolation

3.1 ScaffoldingTo do Unit tests, we have to provide replacements for parts of the program that we will omit from the test.

Scaffolding is any code that we write, not as part of the application, but simply to support the process of Unit and Integration testing.

Scaffolding comes in two forms

Drivers

Stubs

3.1.1 Drivers

A driver is test scaffolding that calls the module being tested.

Often just a simple main program that reads values, uses them to construct ADT values, apply ADT operations and print the results

3.1.2 Stubs

Stubs are replacements for code begin called from the unit under test

Must match the “real” APIMay need to provide simulated output parameters and return values

Page 182: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4 Integration TestingIntegration testing is testing that combines several modules, but still falls short of exercising the entire program all at once.

Integration testing usually combines a small number of modules that call upon one another.

Integration testing can be conducted

bottom-up

(start by unit-testing the modules that dont’call anything else, then add the modules that call those starting modules and thest the combination, thenadd the modules that call those, and so on until you are ready to test main().)

relieves the need for stubs

or top-down

(start by unit-testing main() with stubs for everything it calls, then replace those stubs by the real code, but leaving in stubs for anything calledfrom the replacement code, then replacng those stubs, and so on, until you have assembled and tested the entire program).

It’s worth noting that unit testing and integration testing can sometimes use some of the same test inputs (and maybe the same expected outputs), because we aretesting the software in different configurations.

Page 183: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Choosing TestsSteven Zeil

Last modified: Dec 21, 2019

Contents:1 Types of testing2 Representative Testing

2.1 The Operational Profile2.2 Reliability Growth Models

3 Directed Testing3.1 Black-Box Testing3.2 White-Box Testing3.3 Reliability Modeling with Directed Tests

Abstract

Testing starts with the design of test cases that express our strategy for testing our code. Where do these come from?

Testing strategies are generally divided into three categories:

Blackbox testing chooses tests based upon the requirements, without consulting the implementation. In fact, black-box tests are often developed beforecoding has even begun.

Whitebox testing chooses tests based upon the details and structure of the implementation.

Representative testing chooses test data based upon projections of how the program will be used in operation.

We will examine each of these possibilities.

1 Types of testingWe can differentiate testing strategies by overall goal:

Statistical testing

tests designed to reflect the frequence of user inputs.

Page 184: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Used for reliability estimation.

Defect testing

tests designed to discover system defects.A successful defect test is one which reveals the presence of defects in a system.

Choosing Test Data

From these motives come different approaches to choosing test data

Representative testing

tests designed to reflect the frequence of user inputs.Used for reliability estimation.

Directed testing

Tests designed to discover system defects.A successful directed test is one which reveals the presence of defects in a system.

2 Representative TestingChoose data that is representative of the way the end users will exercise the software.

Advantages:realism — catches the kinds of failures that the users would have encounteredrelatively cheap to generate teststime to failure during test reflects time to failure in operation

useful in statistical reliability modeling

Producing Representative Tests

Test data can be obtained via

collected data from an existing system

A useful option when we are modifying an existing system, which is probably more common than projects where we build a new system from scratch.

“System” here is generic. Even if the old system was completely manual, we may be able to collect and then digitize input data to the old system.

Page 185: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

further selection may be needed

cannot accomodate new functionality

random generators

non-uniform, to match desired distribution

The conventional rand() function yields a uniform distribution — each possible output is equally likely. But random number generators can beimplemented for just about any probability distribution – normal, exponential, etc.

can be hard to generate non-numeric ADT values

Think about the problem of generating random strings to serve as names. If you simply generate sequences of randomly selected lengthcontaining randomly selected characters, the results won’t be very name-like and may strain the ability of code for dealing with fist & last names,etc. Such random strings also tend to look alike ot the human eye, making the visual evaluation of test output nearly impossible.

What I have done in the past is to get lists of common first names and separate lists of real last names (publicly available U.S. census data is greatfor that, BTW). Then randomly select one first name and one last name and combine them together. Granted, you do get some interesting ethniccombinations that way, e.g., “Nguyen Smith” or “Antonio O’Reilly”.

Now consider the further problem of randomly generating a list of customer transactions, of which these names are one component. Now you havethe further problem of how often a particular customer name should be repeated. If you randomly generate a name for each transaction, you willwind up with almost no repeats, and that could lead to some very unrealistic transaction sequences.

Representative Testing

Requires an operational profile for its definitionThe operational profile defines the expected pattern of software usage

2.1 The Operational ProfileThe operational profile is a description of the probability distribution of the input.

It describes how often, during operational program use, certain “kinds” of inputs will be seen.

Sample Op Profile

Input Category PercentageTransaction Proc. 85%

Page 186: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Input Category PercentageBalancing 14%Year-end Report 1%

For an accounting program, we might start with an observation that past activities have broken down like this.

But then we might note that transactions come in many different kinds…

Sample Op Profile

Input Category PercentageTransaction Proc. 85%

New account 7%Close account 3%Debits 70%Credits 20%

Balancing 14%Year-end Report 1%

After noting that the requirements specify different behaviors for transaction on existing accounts and non-existent accounts, we might look at companyrecords for still more statistics…

Sample Op Profile

Input Category PercentageTransaction Proc. 85%

New account 7%new 90%already exists 10%

Close account 3%non-existent 15%exists 85%

Debits 70%non-existent 25%exists 75%

Credits 20%

Page 187: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Input Category Percentagenon-existent 25%exists 75%

Balancing 14%Year-end Report 1%

The breakdown of transactions into cases bases on whether the account is new (non-existent) versus already existing suggests something of an answer to theearlier discussion of randomly generating customer names and asking how often they should repeat. By explicitly measuring how often a new transactioninvolves an existing account, we know whether to randomly generate a new name or to randomly select from among already-generated ones.

Representative testing difficulties

Uncertainty in the operational profile

This is a particular problem for new systems with no operational history. Less of a problem for replacement systems

High costs of generating the operational profile

Costs are very dependent on what usage information is collected by the organisation which requires the profile

Statistical uncertainty

Difficult to estimate level of confidence in operational profileUsage pattern of software may change with time

One example of such changes are so-called “secondary effects” in which the very existence of a new system itself alters the way in which its usersbehave. One of the classic examples of secondary effects is the U.S. Interstate Highway system. The earliest stretches completed in this systemsoon became heavily congested as the number of vehicles using them far exceeded initial estimates. Part of the problem was that the very existenceof the Interstate Highway system enabled urban workers to live and commute from well outside the city limits, so that a road system designed foruse in moving from one city to the next instead was used as the daily rush-hour commutes between urban centers and the suburbs.

2.2 Reliability Growth ModelsA growth model is a mathematical model of the system reliability change as it is tested and faults are removed

Used as a means of reliability prediction by extrapolating from current data

Reliability modeling procedure

Page 188: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Determine operational profile of the software

Generate a set of test data corresponding to the profile

Apply tests, measuring amount of execution time between each failure

After a statistically valid number of tests have been executed, reliability can be measured

Reliability metrics

Some common metrics1 that come out of these statistical models are:

Probability of failure on demand

This is a measure of the likelihood that the system will fail when a service request is madePOFOD = 0.001 means 1 out of 1000 service requests result in failureRelevant for safety-critical or non-stop systems

Rate of fault occurrence (ROCOF)

Frequency of occurrence of unexpected behaviourROCOF = 0.02 means 2 failures are likely in each 100 operational time unitsRelevant for operating systems, transaction processing systems

Mean time to failure

Measure of the time between observed failuresMTTF = 500 means that the average time between failures is 500 time unitsRelevant for systems with long transactions e.g. CAD systems

Availability

Measure of how likely the system is available for use. Takes repair/restart time into accountAvail = 0.998 means software is available for 998 out of 1000 time unitsRelevant for continuously running systems e.g. telephone switching systems

2.2.1 Collecting data for reliability measurement

Measure the number of system failures for a given number of system inputs

Used to compute POFOD

Page 189: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Measure the time (or number of transactions) between system failures

Used to compute ROCOF and MTTF

Measure the time to restart after failure

Used to compute Avail

Time units

Time units in reliability measurement must be carefully selected. Not the same for all systems

Raw execution time (for non-stop systems)

Calendar time (for systems which have a regular usage pattern e.g. systems which are always run once per day)

Number of transactions (for systems which are used on demand)

2.2.2 Jelinski-Moranda Model

Assumptions:

Software contains faults ( is unknown)

Each fault manifests (causes a failure) at rate

Faults manifest independently

Faults are fixed perfectly, without introducing new ones

If we have repaired faults, the program’s failure rate is

Observed reliability growth

Simple equal-step model but does not reflect reality

Reliability does not necessarily increase with change as the change can introduce new faults

The rate of reliability growth tends to slow down with time as frequently occurring faults are discovered and removed from the software

N N

ϕ

i λ

= (N − i)ϕλi

Page 190: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.2.3 Musa Logarithmic Poisson Model

Assumptions:

Software can never be completely free of faults.

Faults manifest independently

Faults are found in decreasing order of failure rate.

The program failure rate before repairing any faults is

Faults are fixed perfectly, without introducing new ones

If we have repaired faults, the program’s failure rate is

Fitting Example

This data shows the failure rate of a program (measured as where was the length of time the testers were able to run the program before seeing afailure.

Here we have fit this data to the Jelinski-Moranda and Musa Logarithmic models. (Because I have plotted this data using a logarithmic scale for the y-axis, the ML model appears as a straight line in this plot.)

λ0

i λ

=λi λ0e−θi

1/t t

Page 191: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3 Directed TestingChoose tests designed to reveal

many faults

as quickly as possible

Choosing Good Test Data

Page 192: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Techniques for selecting directed test data are generally termed either

white-box, orblack-box

3.1 Black-Box TestingBlack-box (a.k.a. specification-based) testing chooses tests without consulting the implementation.

based simply upon our understanding of what the unit is supposed to do.

One of the goals of black-box testing is to be sure that every distinct behavior expected of a unit has been triggered in at least one test. Another is to try tochoose tests that are likely to cause trouble, no matter what the actual algorithm is.

Some of the best-known techniques for choosing black-box tests focus on the input values that will be supplied to the unit during testing.

Functional Coverage

a.k.a Equivalence partitioning

Choose at least one test that covers each distinct “behavior” described in the requirements.

Different functions performed by the programDifferent types or ranges of input that get treated or described separately.Different types or ranges of output that get treated or described separately.

Large, structured projects place emphasis on tracking requirements to functional test cases

Boundary Values Testing

a.k.a., Extremal Values Testing

Choose as test data the largest and the smallest values for each input and for each “functional” caseOften misunderstood as simply choosing largest & smallest possible inputsAssumes that we have started by attempting functional coverage

Special Values Testing

Choose as test data those certain data values that just tend to cause trouble.

Page 193: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Programmers eventually develop a sense for these. They include

For integers: -1, 0, 1

For floating point numbers: -e, 0, +e, where “e” is a very small number

For strings: the empty string, strings containing only blanks, strings containing no alphabetic characters

What is “Special”?

As we move to other data structures, we may develop a suspicion of other special values, e.g.,

For times of the day: midnight, noonFor containers of data: an empty container

Special values and Boundary values often overlap

(F14 example)

3.2 White-Box TestingWhite-Box (a.k.a. Implementation-based testing) uses information from the implementation to choose tests.

Formally, most white-box testing involves coverage measures, E.g., statement coverage, branch coverage

For example, a common goal in white-box testing is to be sure that every code statement is executed at least once by some test. Another common goal isthat, for every conditional branch (ifs, loops, etc.) in the code, that on at least one test that condition will have been true and on at least one test thatcondition will have been false.

The difficulty with such white-box testing is that it’s almost impossible to be sure you have met one of these goals unless you have special testingsoftware to track the execution of statements and branches over the whole history of testing. Lacking this software, it’s easier to do black-box testing.

Informally, design tests specifically to exercise “tricky” parts of the code

However, there is a kind of informal white-box testing that we can do. As programmers, we often write a bit of code and think to ourselves “I wonder ifthis is really going to work?” That’s a good time to pause and design a test that will check exactly that bit of dicey code.

Common forms:

Structural Testing (a.k.a., “path testing” (not per your text)

Page 194: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Designate a set of paths through the program that must be exercised during testing.

Statement CoverageBranch CoverageCyclomatic coverage (“independent path testing”)Data-flow Coverage

Mutation testing

Perturbation testing

3.2.1 Statement Coverage

Require that every statement in the code be executed at least once during testing.

Special programs (“software tools”) will monitor this requirement for you.

gprof in GNU gcc/g++ suiteClover and JaCoCo for Java

Example

cin >> x >> y; while (x > y) { if (x > 0) cout << x; x = f(x, y); } cout << x;

What kinds of tests are required for statement coverage?

3.2.2 Branch Coverage

Requires that every “branch” in the flowchart be tested at least once

Equivalent to saying that each conditional stmt must be tested as both true and falseBranch coverage implies Statement Coverage, but not vice versa

if X < 0 then X := -X;

Page 195: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Y := sqrt(X);

Branch Coverage example

cin >> x >> y; while (x > y) { if (x > 0) cout << x; x = f(x, y); } cout << x;

What kinds of tests are required for branch coverage?

3.2.3 Cyclomatic Coverage

(a.k.a “independent path coverage”, “path testing”)

The latter term (used in your text) should be discouraged as it is both vague and means something entirely different to most of the testing community

Each independent path must be tested

An independent path is one that includes a branch not previously taken.

A Control Flow Graph

What are the independent paths?

1, 2, 3, 4, 12, 13

1, 2, 3, 5, 6, 11, 2, 12, 13

1, 2, 3, 5, 7, 8, 10, 11, 2, 12, 131, 2, 3, 5, 7, 9, 10, 11, 2, 12, 13

Page 196: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.2.4 Cyclomatic Complexity

The number of independent paths in a program can be discovered by computing the cyclomatic complexity (McCabe, 1976)

This is a popular metric for module complexity.

Actually pretty trivial: for structured programs with only binary decision constructs, equals number of conditional statements +1

relation to testing is dubious

simply branch coverage hidden behind smoke and mirrors

Uniqueness

CC(G) = Number(edges) − Number(nodes) + 1

Page 197: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Sets of independent paths are not unique, nor is their size.

Earlier we gave this set of 4 paths as a cover

1, 2, 3, 4, 12, 131, 2, 3, 5, 6, 11, 2, 12, 131, 2, 3, 5, 7, 8, 10, 11, 2, 12, 131, 2, 3, 5, 7, 9, 10, 11, 2, 12, 13

All are independent.

But this set of two paths also covers all

1, 2, 3, 5, 6, 11, 2, 3, 5, 7, 8, 10, 11, 2, 3, 5, 7, 9, 10, 11, 2, 12, 131, 2, 3, 4, 12, 13

And there are no paths independent of these two.

3.2.5 Data-Flow Coverage

Attempts to test significant combinations of branches.

Any stmt i where a variable X may be assigned a new value is called a definition of X at i: def(X,i)

Any stmt i where a variable X may be used/retrieved is called a reference or use of X at i: ref(X,i)

def-clear

A path from stmt i to stmt j is def-clear with respect to X if it contains no definitions of X except possibly at the beginning (i) and end (j)

all-defs

The all-defs criterion requires that each definition def(X,i) be tested some def-clear path to some reference ref(X,j).

Page 198: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1: cin >> x >> y; d(x,1) d(y,1)2: while (x > y) r(x,2), r(y,2)3: {4: if (x > 0) r(x,4)5: cout << x; r(x,5)6: x = f(x, y); r(x,6), r(y,6), d(x,6)7: }8: cout << x; r(x,8)

What kinds of tests are required for all-defs coverage?

all-uses

The all-uses criterion requires that each pair (def(X,i), ref(X,j)) be tested using some def-clear path from i to j.

1: cin >> x >> y; d(x,1) d(y,1)2: while (x > y) r(x,2), r(y,2)3: {4: if (x > 0) r(x,4)5: cout << x; r(x,5)6: x = f(x, y); r(x,6), r(y,6), d(x,6)7: }8: cout << x; r(x,8)

What kinds of tests are required for all-uses coverage?

3.2.6 Mutation Testing

Given a program ,

Form a set of mutant programs that differ from by some single change

These changes (called mutation operators) include:

exchanging one variable name by anotheraltering a numeric constant by some small amountexchanging one arithmetic operator by anotherexchanging one relational operator by anotherdeleting an entire statementreplacing an entire statement by an abort() call

but can be almost any single small change.

P

P

Page 199: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Mutation Testing (cont.)

Run and each mutant on a previously chosen set of tests

Compare the output of each to that of

If the outputs differ on any test, is killed and removed from the set of mutant programsIf the outputs are the same on all tests, is still considered alive.

Mutation Testing (cont.)

A set of test data is considered inadequate if it cannot distinguish between the program as written ( ) and programs that differ from it by only a simple change.

So if any mutants are still alive after running a set of tests, we augment the tests until we can kill all the mutants.

Mutation Testing Problems

Even simple programs yield tens of thousands of mutants. Executing these is time-consuming.

But most are killed on first few testsAnd the process is automated

Some mutants are actually equivalent to the original program:

⋮ ⋮ X = Y; X = Y; if (X > 0) then if (Y > 0) then} ⋮ ⋮

Identifying these can be difficult (and cannot be automated)

3.2.7 Perturbation Testing

Perturbation testing (Zeil) treats each arithmetic expression in the code as if it had been modified by the addition of an error term , where are the program variables and can be a polynomial of arbitrarily high degree (can approximate almost any error)

Monitor the variable values actually encountered during testing

Solve for the possible functions that would have escaped detection on the tests done so far

If there are none, we’re done.

P Pi

Pi P

Pi

Pi

P

f( )x̄ f( ) + e( )v̄ v̄ v

e

e

Page 200: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

If some exist, can generally be expressed as “coincidental” relations between variablese.g., x and y have always been equal in all tests, so substitutions of one for the other could yet not have been detected

3.3 Reliability Modeling with Directed TestsMost literature on reliability models assumes that it can only be done with representative testing, because

Directed tests’ time-to-failure is unrelated to operational time-to-failure

Directed tests may find faults “out of order”

Order Statistic Model

Zeil & Mitchell (1996) presented a model for reliability growth under either representative or directed testing.

Assumptions:

Software contains faults, whose failure rates are described by a distribution .

Faults manifest independently

The test process is biased towards finding faults with higher failure rates.

Measurement Process

Fault failure rates are measured when the fault has been identified and corrected.

“post-mortem” analysis

Faults are then sorted by failure rate.

The sorted data is fitted to an order statistic distribution.

Order statistics is the study of the probability of selecting certain values when the selection process is biased.

Fitting Example

N F

Page 201: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

This plot shows an alternative scenario in which the testers started by using representative testing, but once the intervals between failures (and, therefore,between fixes) became lengthy, switched to directed testing to accelerate the process of actually finding and fixing bugs. The Order Statistic model is able, aftera period of adjustment to the new testing approach, to model (predict) the severity of the remaining bugs.

1: For some reason, in this field people like to talk about “metrics” rather than the entirely equivalent but less impressive sounding “measures”.

Page 202: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Automating the Testing OracleSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Automating the Oracle

1.1 How can oracles be automated?1.2 Examining Output1.3 Limitations of Capture-and-Examine Tests

2 Self-Checking Unit & Integration Tests2.1 First Cut at a Self-Checking Test2.2 Better Idea: Test the Public Functions Against Each Other2.3 assert() might not be quite what we want

3 JUnit Testing3.1 JUnit Basics3.2 Structure of a JUnit Test3.3 A JUnit Example3.4 Setting Up Tests3.5 Writing Expressive Tests3.6 Matchers3.7 JUnit in Eclipse

4 C++ Unit Testing4.1 Google Test4.2 Boost Test Framework4.3 CppUnitLite

Earlier we introduced this model of the basic testing process.

In this lesson, we turn our attention to the oracle, the process for determining whether a test has failed.

We will argue that the economics of testing provide a powerful incentive to automate the oracle. Traditionally, this has been done by capture-and-examine,capturing outputs and then using a separate automated process to examine and pass judgement upon those outputs.

Current practice, however, emphasizes self-checking tests, drivers that both feed input to the code under test and immediately evaluating its responses. Self-checking tests are supported by a *Unit framework. We will look at popular frameworks for both Java and C++.

Page 203: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1 Automating the Oracle

Why Automate the Oracle?

Most of the effort in large test suites is evaluating correctness of outputs

The oracle is a decision procedure for deciding whether the output of a particular test is correct.

Humans (“eyeball oracles”) are notoriously unreliable

better to have tests check themselves.

Regression test suites can be huge.

Thousands, tens of thousands, even hundreds of thousands of tests are not unheard of. If your idea of testing is running some code and visually inspectingthe output, you can see that won’t work on this kind of scale. Regression tests have almost always been designed to check themselves. Often this wasdone by recording, during unit, integration, or systems test, the outputs produced by each test input. During regression testing, the same inputs are rerun,and the outputs compared to the earlier ones that had been recorded. If the outputs change, an alert is printed. If the outputs stay the same, testing movesquietly on to the next test.

Modern development methods emphasize rapid, repeated unit tests

It might not be obvious that self-checking is quite valuable for unit and integration testing as well. But if test outputs have to be inspected by a human,then anything more than a very few tests becomes a tedious thing to do. This motivates programmers to write very few tests and to run them infrequently,both of which are very bad ideas.

Page 204: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Test-driven development: Develop the tests first, then write the code.

In fact, many of the latest trends in software development place a lot more emphasis on almost continual unit testing. In so-called agile or extremeprogramming, programmers are expected to write tests before implementing their functions or ADTs, and to continually rerun the tests as units areadded or changed. (In effect, we get a kind of “rolling” integration test.)

In continuous integration processes, every time a programmer stops work on a unit, not only are its unit tests run, but the changes are automaticallyintegrated into the entire program, and integration and systems tests are re-run.

But that's just not going to happen if testing is hard to do.

Debugging: if you can’t reproduce the error, how will you know when you’ve fixed it?

If a bug is reported or a new feature requested, the first step is to add new tests that fail because of the bug or missing feature. Then we will know we havesuccessfully fixed the problem when we are able to pass that test.

The best way to be sure programmers rerun the tests on a regular basis is to make the test run part of the regular build process (e.g., build the test runs into theproject make file) and to make them self-checking.

1.1 How can oracles be automated?Output Capture

If we are doing systems/regression tests, the first step towards automation is to capture the output:

If a program produces output files, one can self-check by creating a file representing the expected correct output, then running the program to get the actualoutput file and using a simple comparison utility like the Unix diff or cmp commands to see if the actual output is identical to the expected output.

For system-level regression tests, this is even simpler. Once we have a program that passes our system tests, we run it on those tests and save the outputs. Thosebecome the expected output files for later regression testing. (Remember, the point of regression testing is to determine if any behavior has changed due torecent updates to the code.)

If the program updates a database, it may be possible to capture entire databases in a similar fashion. Alternatively, we write database queries to check forchanges in the records most likely to have been affected by a test.

On the other hand, if the program’s main function is to present information on a screen, self-checking is very difficult. Screen captures are often not much use,because we are unlikely to want to deal with changes where, say one window is a pixel wider or a pixel to the left of where it had been in a prior test. Self-checking tests for programs like this either require extremely fine control over all possible interactive inputs and graphics device characteristics, or they requirea careful “design for testability” to record, in a testing log file, information about what is being rendered on the screen. (We’ll revisit this idea later in thesemester when we discuss the MVC pattern for designing user interfaces.)

Page 205: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Output Capture and Drivers

At the unit and integration test level, we are testing functions and ADT member functions that most often produce data, not files, as their output. That data couldbe of any type.

How can we capture that output in a fashion that allows automated examination?

Traditional answer is to rely on the scaffolding to emit output in text form.

A more sophisticated answer, which we will explore later, is to design these tests to be self-checking.

1.2 Examining Output

1.2.1 File Tools

diff, cmp and similar programs compare two text files byte by byteused to compare expected and actual outputuseful in back-to-back testing of

old system to its new replacementsystem before and after a bug repairbut also used with manually generated expected output

parameters allow special treatments of blanks, empty lines, etc.some versions can be used with binary files

Alternatives

More sophisticated tests can be performed via grep and similar utilitiessearch file for data matching a regular expression

Custom oracles

Some programs lend themselves to specific, customized oracles

For example, a program to invert a matrix can be checked by multiplying its input and output together — should yield the identity matrix.

pipe output from program/driver directly into a custom evaluation program, e.g.,

testInvertMatrix matrix1.in > matrix1.out multiplyCheck matrix1.in < matrix1.out

Page 206: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

or

testInvertMatrix matrix1.in | multiplyCheck matrix1.in

Most useful when oracle can be written with considerably less effort than the program under test

1.2.2 expect

expect is a shell for testing interactive programs.

an extension of TCL (a portable shell script).

Key expect Commands

spawn: Launch an interactive program.

send: Send a string to a spawned program, simulating input from a user.

expect: Monitor the output from a spawned program. Expect takes a list of patterns and actions:

pattern1 {action1} pattern2 {action2} pattern3 {action3} ⋮

and executes the first action whose pattern is matched.

Patterns can be regular expressions or simpler “glob” patterns

interact: Allow person running expect to interact with spawned program. Takes a similar list of patterns and actions.

Sample Expect Script

Log in to other machine and ignore “authenticity” warnings.

#!/usr/local/bin/expectset timeout 60 spawn ssh $argvwhile {1} { expect {

Page 207: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

eof {break} "The authenticity of host" {send "yes\r"} "password:" {send "$password\r"} "$argv" {break} # assume machine name is in prompt } } interact close $spawn_id

Expect: Testing a program

puts "in test0: $programdir/testsets\n" catch { spawn $programdir/testsets ➀ expect \ ➁ "RESULT: 0" {fail "testsets"} \ ➂ "missing expected element" {fail "testsets"} \ "contains unexpected element" {fail "testsets"} \ "does not match" {fail "testsets"} \ "but not destroyed" {fail "testsets"} \ {RESULT: 1} \{pass "testsets"} \ ➃ eof {fail "testsets"; puts "eofbsl nl"} \ timeout {fail "testsets"; puts "timeout\n"} } catch { close wait }

➀ Launches the testsets program

➁ Watches the output for one of the following conditions

➂ The “RESULT” line is the normal output. A result of 0 is a test case failure.

➃ A result of 1 is a test case success

The various other options are diagnostic/error messages that could appear if the program never reaches the RESULT output.

1.3 Limitations of Capture-and-Examine Tests

Page 208: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Structured Output

For unit/integration test, output is often a data structure.

Data must be serialized to generate text output and parsed to read the subsequent input

A lot of work

Easy to omit detailsCan introduce bugs of its own

Similar issues can exist with the need to supply structured inputs

Repository Output

For system and high-level unit/integration tests, output may be updates to a database or other repository.

Must be indirectly “captured” via subsequent query/accesssignificant setup and cleanup effort per test

need separate test stores

Graphics Output

For system and high-level unit/integration tests, output may be graphics

very hard to capture

Similar issues can arise supplying GUI input

Supplying a repeatable sequence of input events (key presses, mouse movement & clicks, etc)Sometimes timing-critical

2 Self-Checking Unit & Integration TestsAddresses problem of capture-and-examine for structured data

Each test case is a function.

That function constructs required inputs …and passes those inputs to the module under test …

Page 209: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

and examines the output …

… all within the memory space of the running function

In testing an ADT, we are not testing an individual function, but a collection of related functions. In some ways that makes thing easier, because we can usemany of these functions to help test one another.

2.1 First Cut at a Self-Checking TestSuppose you were testing a SetOfInteger ADT and had to test the add function in isolation, you would need to know how the data was stored in the set andwould have to write code to search that storage for a value that you had just added in your test. E.g.,

void testAdd (SetOfInteger aSet) { aSet.add (23); bool found = false; for (int i = 0; i < aSet.numMembers && !found; ++i) found = (aSet[i] == 23); assert(found); }

2.1.1 What’s Good and Bad About This?

void testAdd (SetOfInteger aSet) { aSet.add (23); bool found = false; for (int i = 0; i < aSet.numMembers && !found; ++i) found = (aSet.data[i] == 23); assert(found); }

Good: captures the notion that 23 should have been added to the set

Good: requires no human evaluation

Bad: relies on underlying data structure

Requires the tester to think at multiple levels of abstractionTest is fragile: if implementation of SetOfInteger changes, test can become uselessMight not even compile - those data members are probably private

Page 210: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.2 Better Idea: Test the Public Functions Against Each OtherOn the other hand, if you are testing the add and the contains function, you could use the second function to check the results of the first:

void testAdd (SetOfInteger aSet) { aSet.add (23); assert (aSet.contains(23)); }

Simpler

Robust: tests remain valid even if data structure changes

Legal: Does not require access to private data

Not only is this code simpler than writing your own search function as part of the test driver, it continues to work even if the data structure used to implementthe ADT should be changed. What’s more, it is, in a sense, a more thorough test, since it tests two functions at once. Finally, there’s the simple fact that the testwith the explicit loop probably won’t even compile, since it refers directly to data members that are almost certainly private.

In a sense, we have made a transition from white-box towards black-box testing. The new test case deliberately ignores the underlying structure.

2.2.1 Idiom: Preserve and Compare

void testAdd (SetOfInteger startingSet) { SetOfInteger aSet = startingSet; aSet.add (23); assert (aSet.contains(23)); if (startingSet.contains(23)) assert (aSet.size() == startingSet.size()); else assert (aSet.size() == startingSet.size() + 1); }

Note that we

save the original ADT value, thenmodify a copy, and thencompare the original and copy to see the changes

2.2.2 More Thorough Tests

Page 211: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

You can see the usefulness of “preserve and comapre” in this more thorough test.

void testAdd (SetOfInteger aSet) { for (int i = 0; i < 1000; ++i) { int x = rand() % 500; bool alreadyContained = aSet.contains(x); int oldSize = aSet.size(); aSet.add (23); assert (aSet.contains(x)); if (alreadyContained) assert (aSet.size() == oldSize); else assert (aSet.size() == oldSize + 1); } }

2.3 assert() might not be quite what we wantOur use of assert() in these examples has mixed results

Good: stays quiet as long as we are passing tests

failures easily detected by humans

Bad: testing always stops at the first failure

In a large suite of many such test cases, we may be missing out on info that would be useful for debugging

Bad: diagnostics are limited to file name and line number where the assertion failed.

3 JUnit TestingJUnit is a testing framework that has seen wide adoption in the Java community and spawned numerous imitations for other programming languages.

Introduces a structure for a

suite (separately executable program) oftest cases (functions),each performing multiple self-checking tests (assertions)

using a richer set of assertion operators

Page 212: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

also provides support for setup, cleanup, report generation

readily integrated into IDEs

3.1 JUnit BasicsGetting Started: Eclipse & JUnit

Let’s suppose we are building a mailing list application. the mailing list is a collection of contacts.

Contact.java +

package mailinglist; /** * A contact is a name and address. * <p> * For the purpose of this example, I have simplified matters * a bit by making both of these components simple strings. * In practice, we would expect Address, at least, to be a * more structured type. * * @author zeil * */public class Contact implements Cloneable, Comparable<Contact> { private String theName; private String theAddress; /** * Create a contact with empty name and address. * */ public Contact () { theName = ""; theAddress = ""; } /** * Create a contact * @param nm name * @param addr address */ public Contact (String nm, String addr) {

Page 213: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

theName = nm; theAddress = addr; } /** * Get the name of the contact * @return the name */ public String getName() { return theName; } /** * Change the name of the contact * @param nm new name */ public void setName (String nm) { theName= nm; } /** * Get the address of the contact * @return the address */ public String getAddress() { return theAddress; } /** * Change the address of the contact * @param addr new address */ public void setAddress (String addr) { theAddress = addr; } /** * True if the names and addresses are equal */ public boolean equals (Object right) { Contact r = (Contact)right; return theName.equals(r.theName) && theAddress.equals(r.theAddress); }

Page 214: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public int hashCode () { return theName.hashCode() + 3 * theAddress.hashCode(); } public String toString() { return theName + ": " + theAddress; } public Object clone() { return new Contact(theName, theAddress); } /** * Compare this contact to another. * Return value > 0 if this contact precedes the other, * == 0 if the two are equal, and < 0 if this contact * follows the other. */ public int compareTo (Contact c) { int nmcomp = theName.compareTo(c.theName); if (nmcomp != 0) return nmcomp; else return theAddress.compareTo(c.theAddress); } }

MailingList.java +

package mailinglist; /** * A collection of names and addresses */public class MailingList implements Cloneable { /** * Create an empty mailing list * */ public MailingList() { first = null; last = null; theSize = 0;

Page 215: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

} /** * Add a new contact to the list * @param contact new contact to add */ public void addContact(Contact contact) { if (first == null) { // add to empty list first = last = new ML_Node(contact, null); theSize = 1; } else if (contact.compareTo(last.contact) > 0) { // add to end of non-empty list last.next = new ML_Node(contact, null); last = last.next; ++theSize; } else if (contact.compareTo(first.contact) < 0) { // add to front of non-empty list first = new ML_Node(contact, first); ++theSize; } else { // search for place to insert ML_Node previous = first; ML_Node current = first.next; assert (current != null); while (contact.compareTo(current.contact) < 0) { previous = current; current = current.next; assert (current != null); } previous.next = new ML_Node(contact, current); ++theSize; } } /** * Remove one matching contact * @param c remove a contact equal to c */ public void removeContact(Contact c) { ML_Node previous = null; ML_Node current = first; while (current != null && c.getName().compareTo(current.contact.getName()) > 0) { previous = current; current = current.next; } if (current != null && c.getName().equals(current.contact.getName())) remove(previous, current); }

Page 216: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

/** * Remove a contact with the indicated name * @param name name of contact to remove */ public void removeContact(String name) { ML_Node previous = null; ML_Node current = first; while (current != null && name.compareTo(current.contact.getName()) > 0) { previous = current; current = current.next; } if (current != null && name == current.contact.getName()) remove(previous, current); } /** * Search for contacts * @param name name to search for * @return true if a contact with an equal name exists */ public boolean contains(String name) { ML_Node current = first; while (current != null && name.compareTo(current.contact.getName()) > 0) { current = current.next; } return (current != null && name == current.contact.getName()); } /** * Search for contacts * @param name name to search for * @return contact with that name if found, null if not found */ public Contact getContact(String name) { ML_Node current = first; while (current != null && name.compareTo(current.contact.getName()) > 0) { current = current.next; } if (current != null && name == current.contact.getName()) return current.contact; else return null; } /** * combine two mailing lists * */ public void merge(MailingList anotherList) {

Page 217: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

// For a quick merge, we will loop around, checking the // first item in each list, and always copying the smaller // of the two items into result MailingList result = new MailingList(); ML_Node thisList = first; ML_Node otherList = anotherList.first; while (thisList != null && otherList != null) { int comp = thisList.contact.compareTo(otherList.contact); if (comp <= 0) { result.addContact(thisList.contact); thisList = thisList.next; /* if (comp == 0) otherList = otherList.next; [Deliberate bug ] */ } else { result.addContact(otherList.contact); otherList = otherList.next; } } // Now, one of the two lists has been entirely copied. // The other might still have stuff to copy. So we just copy // any remaining items from the two lists. Note that one of these // two loops will execute zero times. while (thisList != null) { result.addContact(thisList.contact); thisList = thisList.next; } while (otherList != null) { result.addContact(otherList.contact); otherList = otherList.next; } // Now result contains the merged list. Transfer that into this list. first = result.first; last = result.last; theSize = result.theSize; } /** * How many contacts in list? */ public int size() { return theSize; } /** * Return true if mailing lists contain equal contacts */ public boolean equals(Object anotherList) { MailingList right = (MailingList) anotherList; if (theSize != right.theSize) // (easy test first!)

Page 218: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

return false; else { ML_Node thisList = first; ML_Node otherList = right.first; while (thisList != null) { if (!thisList.contact.equals(otherList.contact)) return false; thisList = thisList.next; otherList = otherList.next; } return true; } } public int hashCode() { int hash = 0; ML_Node current = first; while (current != null) { hash = 3 * hash + current.contact.hashCode(); current = current.next; } return hash; } public String toString() { StringBuffer buf = new StringBuffer("{"); ML_Node current = first; while (current != null) { buf.append(current.contact.toString()); current = current.next; if (current != null) buf.append("\n"); } buf.append("}"); return buf.toString(); } /** * Deep copy of contacts */ public Object clone() { MailingList result = new MailingList(); ML_Node current = first; while (current != null) { result.addContact((Contact) current.contact.clone()); current = current.next; } return result; }

Page 219: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

private class ML_Node { public Contact contact; public ML_Node next; public ML_Node(Contact c, ML_Node nxt) { contact = c; next = nxt; } } private int theSize; private ML_Node first; private ML_Node last; // helper functions private void remove(ML_Node previous, ML_Node current) { if (previous == null) { // remove front of list first = current.next; if (last == current) last = null; } else if (current == last) { // remove end of list last = previous; last.next = null; } else { // remove interior node previous.next = current.next; } --theSize; } }

Set up an Eclipse project with these two files

Make sure that these compile successfully with no errors.

In the Eclipse Build Path, add a library: JUnit,

Choose JUnit4 if given a choice of versions 3 or 4

3.2 Structure of a JUnit Test

Page 220: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A JUnit test is a class.

It contains one or more “test cases” or “test functions” – member functions that return void, take no parameters, and are marked with @Test.

Each test case

1. Sets up any necessary test data.2. Runs the code to be tested on that data.3. Examines the results of the test via one or more assertions.

A test case can

1. Succeed if all assertions are true.2. Fail if any assertion is false (or if the fail(...) function is called explicitly).3. Terminate with an error if the test case itself throws an exception.

3.2.1 Assertions

assertTrue( condition ): condition should be true.assertFalse( condition ): condition should be false.assertEquals( x , y): x and y should be equal. (For objects, this is tested using the equals(...) function. For primitives like int, the == operator isused.)assertEquals( x , y , delta): Floating point numbers x and y should be approximately equal, within plus or minus delta.assertArrayEquals( array1 , array2): array1 and array2 should have the same length and corresponding elements in these arrays should be equal.assertSame( obj1 , obj2): obj1 and obj2 should hold the same address.assertNotSame( obj1 , obj2): obj1 and obj2 should not hold the same address.assertNull( obj1 ): obj1 should be a null reference.assertNotNull( obj1 ): obj1 should not be a null reference.

Each of these can have an optional first argument of a string that will be printed when the assertion fails. For example,

Integer pos = search(arr, x); assertNotNull (pos); assertNotNull ("Could not find x in arr", pos);

3.3 A JUnit Example

3.3.1 A First Test Suite

Right-click on the project and select New ... JUnit Test Case.

Page 221: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Give it a name (e.g., TestMailingList)

in the same mailinglist package as the two classes

For “Class under test”, use the Browse button and select our MailingList class

Click Next, then select the MailingList() and addContact( … ) functions

3.3.2 A First Test Suite (cont.)

You’ll get something like this:

package mailinglist; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; public class TestMailingList { @Test public void testMailingList() { fail("Not yet implemented"); } @Test public void testAddContact() { fail("Not yet implemented"); } }

Save this, and run it (right-click on the new file in the Package Explorer, and select Run As ... JUnit Test)

You’ll see what failed tests look like.Try double-clicking on the failed cases and observe the effects on the source code listing and the Failure Trace

3.3.3 A First Test

Let’s implement a test for the mailing list constructor.

/** * Create an empty mailing list *

Page 222: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

*/public MailingList() {

Glancing through the MailingList interface, what would we expect of an empty mailing list?

the size() would be zero

any contact we might search for would not be contained in the list

3.3.4 Testing the Constructor

Change the testMailingList function to

testmlConst.java +

@Testpublic void testMailingList() { MailingList ml = new MailingList(); ➀ assertFalse (ml.contains("Jones")); ➁ assertNull (ml.getContact("Smith")); assertEquals (0, ml.size()); ➂ }

➀ Before we can test any function, we have to invoke it

➁ Notice the tests using different variations on the idea of an assertion

assert( ... ) itself remains a language primitive - we don’t use that but use these JUnit variations insteadUse assertTrue instead of assertThe JUnit versions don’t shut down all testing the way the primitive assert( ... ) would do

The first failed JUnit assertion shuts down the test case (function)

➂ The order of parameters in assertEquals is significant

expected value comes first

3.3.5 Running the Constructor Test

Run the test suite as beforeIt should succeed (testAddContact will still fail)

Change the “0” in the final test to “1”. Run again, and observe the message in the Failure Trace.Restore the “0”. Change the first line to

Page 223: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

MailingList ml = null; // new MailingList();

and run again.

Notice that a “test error” is marked differently than a “failed test”

Restore the first line

3.3.6 Testing addContact

Now let’s add a test for addContact:

After adding a contact

the size() should increase

the contact name should be contained in the list

we should be able to find the contact that we just added.

Testing addContact - first pass

Try this test (run it!)

@Testpublic void testAddContact() { MailingList ml = new MailingList(); Contact jones = new Contact("Jones", "21 Penn. Ave."); ml.addContact (jones); assertTrue (ml.contains("Jones")); assertFalse (ml.contains("Smith")); assertEquals ("Jones", ml.getContact("Jones").getName()); assertNull (ml.getContact("Smith")); assertEquals (1, ml.size()); }

It works. But it feels awfully limited.

3.4 Setting Up Tests

Page 224: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Before we try making that test more rigorous, let’s look at how we can organize the set up of auxiliary data like our contacts:

Contact jones; @Beforepublic void setUp() throws Exception { jones = new Contact("Jones", "21 Penn. Ave."); } ⋮ @Test public void testAddContact() { MailingList ml = new MailingList(); ml.addContact (jones); ⋮

3.4.1 Fixtures

The class that contains the data shared among the tests in a suite is called a fixture.

A function marked as @Before will be run before each of the test case functions.

Used to (re)initialize data used in multiple tests

Why every time?

Helps keep test cases independentDuring debugging, it’s common to select and run single test cases in isolation

Can do cleanup in a similar fashion with “@After”

3.4.2 Testing addContact - setup

Contact jones; Contact baker; Contact holmes; Contact wolfe; MailingList mlist; @Beforepublic void setUp() throws Exception { jones = new Contact("Jones", "21 Penn. Ave."); baker = new Contact("Baker", "Drury Ln."); holmes = new Contact("Holmes", "221B Baker St."); wolfe = new Contact("Wolfe",

Page 225: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

"454 W. 35th St."); mlist = MailingList(); mlist.addContact(baker); mlist.addContact (holmed); mlist.addContact (baker); }

Create a series of contacts

3.4.3 Testing addContact - improved

@Testpublic void testAddContact() { assertTrue (mlist.contains("Jones")); assertEquals ("Jones", mlist.getContact("Jones").getName()); assertEquals (4, ml.size()); }

Still seems a bit limited - we’ll address that later.

3.5 Writing Expressive TestsOne goal is writing tests is to make them both easy to read and to set them up so that the messages they issue upon failure are as helpful as possible.

3.5.1 Choose the most limited assertion.

These two assertions mean the same thing:

assertTrue(string1.equals(string2)); assertEquals(string1, string2);

I would argue that the second is easier to read. Moreover, if these assertions fail, the second gives a more informative message:

import static org.junit.Assert.*; import org.junit.Test; public class testMessages { String string1 = "abcdef"; String string2 = "abcZef";

Page 226: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

@Test public void test1() { assertTrue (string1.equals(string2)); } @Test public void test2() { assertEquals (string1, string2); } }

results in the messages:

test1: java.lang.AssertionError at testMessages.java:14test2: org.junit.ComparisonFailure: expected:<abc[d]ef> but was:<abc[Z]ef> at testMessages.java:19

The second message is clearly more helpful.

You can alleviate this a bit by adding a message

assertTrue ("string1 is not equal to string2", string1.equals(string2));

but, really, it’s still not as good.

Use assertTrue and assertFalse only when more specific assertions do not apply. Then consider adding messages to them explaining what theyare actually checking for.

For example, if what we really wanted to assert was that one string contained the other, then we would be stuck with

assertTrue ("string1 does not contain " + string2", string1.contains(string2));

3.6 MatchersBecause the set of basic assertions is, of necessity, limited, a newer style of assertion has arisen that

1. Tries to be more expressive for many common tests.

Page 227: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2. Can be extended to new “kinds” of assertions fitted to custom ADTs.

The assertion style looks like

assertThat (object, matcher);

(Again, an optional message can be added to the front of the parameter list, but it is generally hopes that the new style reduces the need for this.)

In this new style,

assertThat (obj1, equalTo(obj2));

means the same thing as

assertEquals (obj1, obj2);

but uses the equalTo matcher instead.

3.6.1 Core matchers

The Hamcrest Matchers include a variety of primitives for checking one value:

x .equalTo( y ): x should be equal to y.

Sometimes abbreviated as x .is( y ).

x .instanceOf( class ): x should be an instance of a particular class

Sometimes abbreviated as x .isA( class ).

x .nullValue(): x should be a null reference.

x .notNullValue(): x should not be a null reference.

x .sameInstance( y ): x and y should hold the same address.

3.6.2 Core matchers – modifiers

Other core matchers are used to modify the way that matchers are applied

not( matcher ): The matcher should return false.

Page 228: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

allOf( matcher1, matcher2, … ); all of the matchers should return true.

anyOf( matcher1, matcher2, … ); at least one of the matchers should return true.

anything(): this matcher always returns true.

With these, we can write assertions like:

assertThat(not(x.equalTo(y)); assertThat(anyOf(nullValue(x), not(x.equalTo(y)));

3.6.3 Additional Matchers

Also in the Hamcrest library, matchers for strings, numbers, iterable containers, etc.:

assertThat(x, lessThan(y)); assertThat(string1, isEmptyOrNullString()); assertThat(string1, startsWith("Hello")); assertThat(myList, hasItem("Smith"); assertThat(myList, contains(smallerList); assertThat(myList, containsInAnyOrder("Jones", "Doe", "Smith");

See the Matchers class API for a full list.

3.7 JUnit in EclipseThe Eclipse IDE for Java includes a copy of the JUnit library.

You need to add it to your project settings.

Right-click on your Java project, select Build Path, Add Libraries..., JUnit, and select JUnit4.

4 C++ Unit Testing4.1 Google TestGoogle Test, a.k.a. gtest, provides a similar *Unit environment for C++

Download & follow instructions to prepare library

Page 229: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

gtest will be added to your project as source codeeasiest is to copy the files from fused-src/gtest/ files into a subdirectory gtest within your project.

For Eclipse support, add the Eclipse CDT C/C++ Tests Runner plugin

Example

This time, the C++ version of the mailing list.

1. Source code is here.Unpack into a convenient directory.

2. With Eclipse create a C++ project in that directory.3. Compile4. Run the resulting executable as a local C++ application5. Run as a *unit test:

Right-click on the binary executable, select “Run as … Run configurations”.Select C/C++ Unit, click “New” buttonOn the “C/C++ Testing” tab, select Tests Runner: Google Tests RunnerClick “Run”

Examining the ADT

mailinglist.h +

#ifndef MAILINGLIST_H#define MAILINGLIST_H #include <iostream>#include <string> #include "contact.h"#include "mlIterator.h" /** A collection of names and addresses */class MailingList { public: typedef MLConstIterator iterator; typedef MLConstIterator const_iterator; MailingList();

Page 230: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

MailingList(const MailingList&); ~MailingList(); const MailingList& operator= (const MailingList&); // Add a new contact to the list void addContact (const Contact& contact); // Does the list contain this person? bool contains (const Name&) const; // Find the contact const Contact& getContact (const Name& nm) const; //pre: contains(nm) // Remove one matching contact void removeContact (const Contact&); void removeContact (const Name&); // combine two mailing lists void merge (const MailingList& otherList); // How many contacts in list? int size() const; bool operator== (const MailingList& right) const; bool operator< (const MailingList& right) const; // Provides iterator over contacts const_iterator begin() const; const_iterator end() const; private: struct ML_Node { Contact contact; ML_Node* next; ML_Node (const Contact& c, ML_Node* nxt) : contact(c), next(nxt) {} }; ML_Node* first; ML_Node* last; int theSize; // helper functions

Page 231: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

void clear(); void remove (ML_Node* previous, ML_Node* current); friend std::ostream& operator<< (std::ostream& out, const MailingList& addr); }; // print list, sorted by Contactstd::ostream& operator<< (std::ostream& out, const MailingList& list); #endif

Should look familiar after the Java version

Examining the Tests

MailingListTests.cpp +

#include "mailinglist.h" #include <string>#include <vector> #include "gtest/gtest.h" namespace { using namespace std; // The fixture for testing class MailingList.class MailingListTests : public ::testing::Test { ➀ public: Contact jones; ➃ MailingList mlist; virtual void SetUp() { jones = Contact("Jones", "21 Penn. Ave."); ➄ mlist = MailingList(); mlist.addContact (Contact ("Baker", "Drury Ln.")); mlist.addContact (Contact ("Holmes", "221B Baker St.")); mlist.addContact (Contact ("Wolfe", "454 W. 35th St.")); } virtual void TearDown() { } };

Page 232: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

TEST_F (MailingListTests, constructor) { MailingList ml; EXPECT_EQ (0, ml.size()); ➁ EXPECT_FALSE (ml.contains("Jones")); } TEST_F (MailingListTests, addContact) { mlist.addContact (jones); ➅ EXPECT_TRUE (mlist.contains("Jones")); ➂ EXPECT_EQ ("Jones", mlist.getContact("Jones").getName()); EXPECT_EQ (4, ml.size()); } } // namespace

Roughly similar to the JUnit tests

➀ The class provides a fixture where data can be shared among test cases

This is optional, but common

➁ Test cases are introduced with TEST_F

First argument identifies the suite (same as fixture name)Second argument names the test caseThe combination must be uniqueUse TEST if you don’t provide a fixture class

➂ The test cases feature assertions similar to those seen in JUnit

EXPECT assertions allow testing to continue after failureASSERT variations also exist that shut down testing on failure

➃ Public members of the fixture class will be visible to all test cases

➄ and are assigned the values during SetUp, run before each test case➅ You can see the fixture members used here

Page 233: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4.2 Boost Test Framework

Boost UTF

Boost is a well-respected collection of libraries for C++.

Many of the new library components of C++11 were distributed in Boost for “beta test”.

Other, more specialized libraries will remain separately distributed.

This include another popular *Unit framework for C++, the Boost Unit Test Framework (UTF).

Basic principles are similar to Google Test

Also has some support for building trees of test suites.

Boost Test

The UTF can be added as a single header #include or, for greater efficiency when dealing with multiple suites, compiled to form a static or dynamiclibrary.

Easiest to start with the single header approach. Download and unpack the Boost library.

Add the Boost include directory to your C++ project’s search path for system headers (#include < ... >)If you re using a makefile, add the -I compiler option, e.g., -I /home/zeil/src/boost/includeIn Eclipse, this is Project ... Properties ... C/C++ Build ... Settings ... GCC C++ compiler ... Includes.

For Eclipse support, use the same Eclipse CDT C/C++ Tests Runner plugin

Example

Again, the C++ version of the mailing list.

1. Source code is here.Unpack into a convenient directory.

2. With Eclipse create a C++ project in that directory.Add path to Boost include directory

3. Compile4. Run the resulting executable as a local C++ application5. Run as a *unit test:

Page 234: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Right-click on the binary executable, select “Run as … Run configurations”.Select C/C++ Unit, click “New” buttonOn the “C/C++ Testing” tab, select Tests Runner: Boost Tests RunnerClick “Run”

Examining the Tests

MailingListTests2.cpp +

#define BOOST_TEST_MODULE MailingList test #include "mailinglist.h" #include <string>#include <vector> #include <boost/test/included/unit_test.hpp> using namespace std; // The fixture for testing mailing lists.class MailingListTests { ➀ public: Contact jones; ➁ MailingList mlist; MailingListTests() { ➃ jones = Contact("Jones", "21 Penn. Ave."); mlist.addContact (Contact ("Baker", "Drury Ln.")); mlist.addContact (Contact ("Holmes", "221B Baker St.")); mlist.addContact (Contact ("Wolfe", "454 W. 35th St.")); } ~MailingListTests() { } }; BOOST_AUTO_TEST_CASE ( constructor ) { ➄ MailingList ml; BOOST_CHECK_EQUAL (0, mlist.size()); ➅ BOOST_CHECK (!mlist.contains("Jones")); } BOOST_FIXTURE_TEST_CASE (addContact, MailingListTests) { ➆ mlist.addContact (jones); ➂

Page 235: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

BOOST_CHECK (mlist.contains("Jones")); BOOST_CHECK_EQUAL ("Jones", mlist.getContact("Jones").getName()); BOOST_CHECK_EQUAL (4, mlist.size()); }

➀ This names the suite.

➁ The class provides a fixture where data can be shared ➂ among test cases

Optional, but commonSimpler in Boost than in Google

Can be any class.Initialization is done in the class constructor instead of in a special function. ➃

➄ Test cases that don’t need anything from a fixture are introduced with BOOST\_AUTO\_TEST\_CASE

Argument names the test case

➅ The assertions have different names but are similar in function and variety to JUnit and GTest

A full list is here.

➆ Test cases that need a fixture are introduced with BOOST_FIXTURE_TEST_CASE

Second argument identifies the fixture classPublic members of the fixture class will be visible to test cases ➂

4.3 CppUnitLiteCppUnitLite is my own C++ test framework, with features:

Supports the newer “matcher” style of JUnit/HamcrestLightweight – requires adding one .h and one .cpp file to a project.Emulates GoogleTest when run within EclipsePortable: works in Linux, MacOs, and Windows with CygWin or MingWUnit tests are time-limited by default (Linux/MacOs only)

But timing functions are turned off when running in a debugger.When running in a debugger, a breakpoint is generated automatically on test assertion failure.

Page 236: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Future versions of this framework are intended to offer a mocking framework that is simpler and more intuitive than currently available elsewhere.

4.3.1 Example

MailingListTestsLite.cpp +

#include "unittest.h" ➀#include "mailinglist.h" #include <string>#include <vector> using namespace std; Contact jones; MailingList mlist; void setUp() { jones = Contact("Jones", "21 Penn. Ave."); mlist = MailingList(); mlist.addContact (Contact ("Baker", "Drury Ln.")); mlist.addContact (Contact ("Holmes", "221B Baker St.")); mlist.addContact (Contact ("Wolfe", "454 W. 35th St.")); } UnitTest (constructor) { ➁ MailingList ml; assertThat (ml.size(), is(0)); ➂ assertFalse (ml.contains("Jones")); } UnitTest (addContact) { setup(); ➃ mlist.addContact (jones); assertTrue (mlist.contains("Jones")); assertThat (mlist.getContact("Jones").getName(), is("Jones")); assertThat (ml.size(), is(4)); assertThat (ml, hasItem(jones)); ➄ }

Page 237: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

➀ Imports the unit test framework.➁ New test cases are introduced by UnitTest or UnitTestTimed.

All tests are time-limited by default (not supported in Windows) but UnitTestTimed overrides the default.

➂ A typical assertion, in the newer “matcher” style favored by JUnit.

➃ In general, UnitTestLite aovoids creating special constructs for things that can easily be done by normal programming, such as running a setupfunction at the start of a test.➄ An example of testing a collection. hasItem searches any data structure that provides iterators.

This could also be written as

assertThat (jones, isIn(ml));

Page 238: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Lab: Unit TestingSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Choose Your Project2 C++ Testing3 Java Testing

This is a self-assessment activity to give you practice in working with unit test frameworks. Feel free to share your problems, experiences, and choices in theForum.

1 Choose Your ProjectFor this lab, you will want a fairly simple program, in C++ or Java, that contains at least one well-defined ADT.

You might find this among some of your old homework for CS250, 330, 361, or 382. If you cannot find anything suitable, you might try

this program from Malik, chapter 12 (or 10 or … It depends on what Edition you have.).

You may want to watch 4.4 Testing: C++, JUnit, Pyunit from CS 330.

If you opt to use the Java Tic-Tac-Toe example, you have a reasonable starting point. However, as discussed during 4.4. Testing: C++ JUnit, Pyunit theexample tests are incomplete. Pick one of the non-Player C++ or Java ADTs.

Pick an ADT (not the main program) for testing.

If you have selected a C++ program, proceed to the next section. If you have selected a Java program, jump ahead (for now) to Java Testing.

2 C++ Testing1. If your original program was in Java, translate it to C++.

2. Set up an Eclipse project for your C++ code.

Page 239: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3. Add either the Google Test or Boost Test framework to your project.

4. Write a very simple unit test to start with - something that just asserts that 1 + 1 == 2.

5. Compile this test, in the presence of your other code (even though it won’t be using that code yet).

You may find it necessary to remove or rename your “real” main() function for this purpose, as the default Eclipse project builder for C++ can’t reallydeal with multiple executables. We’ll have to live with this until we learn how to add custom build managers.

6. Run the test driver as a “normal” C++ executable program.

7. Run the test driver as a unit test under the Eclipse framework. You should see the Eclipse GUI report on the number of test successes.

8. Now replace that simple test with a real set of tests for your chosen ADT.

If you are attempting this lab before we have covered ADT testing, use your best general Black-box skills. After we have covered ADT testing, return andexamine your tests from a mutator/accessor perspective. What, if anything, would you add for a good ADT test?

9. Again, run your tests both as normal executable programs and as unit tests under the Eclipse framework.

10. If you have all of your tests in a single .cpp file, try splitting them into two test sets in separate .cpp files. Or, if your program has more than one ADT,write a test or two for the other ADT in a separate .cpp file.

Again, verify that you can compile and run these tests under the Eclipse Framework.

3 Java Testing1. If your original program was in C++, translate it to Java.

2. Set up an Eclipse project for your Java code.

3. Add the JUnit library to the build path of your Java project.

4. Write a very simple unit test to start with - something that just asserts that 1 + 1 == 2.

5. Compile this test.

6. Run the test driver as a unit test under the Eclipse framework. You should see the Eclipse GUI report on the number of test successes.

7. Now replace that simple test with a real set of tests for your chosen ADT.

Page 240: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

If you are attempting this lab before we have covered ADT testing, use your best general Black-box skills. After we have covered ADT testing, return andexamine your tests from a mutator/accessor perspective. What, if anything, would you add for a good ADT test?

8. Again, run your tests under the Eclipse framework.

9. If you have all of your tests in a single .java file, try splitting them into two test sets in separate .java files. Or, if your program has more than one ADT,write a test or two for the other ADT in a separate .java file.

Again, verify that you can compile and run these tests under the Eclipse Framework.

If your original program was Java, and you skipped the C++ section initially, go back now and do the C++ portion of this lab.

Page 241: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Testing ADTsSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Be Smart: Generate and Check

1.1 Generate and Check2 Be Thorough: Mutators and Accessors

2.1 Example: Unit Testing of the MailingList Class2.2 Testing for Pointer/Memory Faults2.3 Case Study 1: Unit Test of NumericLiteral2.4 Is this Overkill?

3 Be Independent:

Abstract

It would be nice if every new ADT we wrote worked correctly the first time it compiled properly, but the real world just doesn’t work that way.

One advantage of organizing your code into a collection of ADTs is that ADTs provide, not only a convenient way to package up the functionality of your code,but also a convenient basis for testing.

The *Unit test frameworks give us a powerful tool for unit testing. But we still need to pick the tests.

In this lesson we look at how to use a unit test framework to “thoroughly” test an ADT. Our approach is based upon dividing the ADT interface into

mutators: functions that alter the state or value of the ADT, andaccessors: functions that examine the state of the ADT.

Our approach then becomes:

1. Each test case explores one mutator, and each mutator has at least one test case.2. In each test case, assert the effect of that mutator as revealed through each accessor.

1 Be Smart: Generate and CheckTesting addContact

Page 242: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

In our earlier test for addContact, we weren’t particularly thorough:

TEST_F (MailingListTests, addContact) { mlist.addContact (jones); EXPECT_TRUE (mlist.contains("Jones")); EXPECT_EQ ("Jones", mlist.getContact("Jones").getName()); EXPECT_EQ (4, ml.size()); }

Missing functional case: adding a contact that already exists

Missing boundary/special case: adding to an empty container

Missing special cases: Adding to beginning or end of an ordered sequence

Adding Variety

Some of our concerns could be addressed by adding tests but varying the parameters:

TEST_F (MailingListTests, addExistingContact) { mlist.addContact (baker); EXPECT_TRUE (mlist.contains("Baker")); EXPECT_EQ ("Baker", mlist.getContact("Baker").getName()); EXPECT_EQ (3, ml.size()); }

1.1 Generate and CheckA useful design pattern for producing well-varied tests is

for v: varieties of ADT { ADT x = generate(v); result = applyFunctionBeingTested(x); check (x, result); }

generate and check could be separate functions or in-line

depends on whether you can re-use in multiple tests

Most common way to introduce “variety” would be size

Page 243: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Could also be different constructors, in which case you might not literally have a loop:

ADT x (constructor1); result = applyFunctionBeingTested(x); check (x, result); ADT x2 (constructor2, ... ); result = applyFunctionBeingTested(x2); check (x2, result);

Example: addContact

A more elaborate fixture will aid in generating mailing lists of different sizes:

fixture.cpp +

// The fixture for testing class MailingList.class MailingListTests { public: Contact jones; vector<Contact> contacts; MailingListTests() { jones = Contact("Jones", "21 Penn. Ave."); contacts.clear(); contacts.push_back (Contact ("Baker", "Drury Ln.")); contacts.push_back (Contact ("Holmes", "221B Baker St.")); contacts.push_back(jones); contacts.push_back (Contact ("Wolfe", "454 W. 35th St.")); } ~MailingListTests() { } MailingList generate(int n) const { MailingList m; for (int i = 0; i < n; ++i) m.addContact(contacts[i]); return m; } };

Page 244: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Example: addContact - many sizes

testAdd1.cpp +

BOOST_FIXTURE_TEST_CASE (addContact, MailingListTests) { for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml (ml0); bool alreadyContained = ml.contains("Jones"); ml.addContact (jones); BOOST_CHECK (ml.contains("Jones")); BOOST_CHECK_EQUAL ("Jones", ml.getContact("Jones").getName()); if (alreadyContained) BOOST_CHECK_EQUAL (ml.size(), sz); else BOOST_CHECK_EQUAL (ml.size(), sz+1); } }

Here we generate mailing lists of a variety of sizes and add Jones to them

At larger sizes, Jones is already in the list – functional case covered

sz == 0 covers one of our boundary/special cases

Example: addContact - ordering

testAdd2.cpp +

BOOST_FIXTURE_TEST_CASE (addContact, MailingListTests) { for (unsigned sel = 0; sel < contacts.size(); ++sel) { Contact& toAdd = contacts[sel]; const Name& nameToAdd = contacts[sel]; for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml (ml0); bool alreadyContained = ml.contains(nameToAdd); ml.addContact (toAdd); BOOST_CHECK (ml.contains(nameToAdd)); BOOST_CHECK_EQUAL (nameToAdd, ml.getContact(nameToAdd).getName()); if (alreadyContained) BOOST_CHECK_EQUAL (ml.size(), sz); else

Page 245: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

BOOST_CHECK_EQUAL (ml.size(), sz+1); } } }

We an also explore adding to different positions (beginning, middle, end)by varying which element we add

2 Be Thorough: Mutators and AccessorsOK, let’s say we want to design a unit test suite for our MailingList ADT.

Just staring at the ADT interface, where do we start? The criteria we suggested earlier (typical values, extremal values, special values) may be of help, but it’sfar from obvious how to apply those ideas.

There is an organized way to approach this test design. It starts with the recognition that the member functions of an ADT can usually be divided into twogroups - the mutators and the accessors.

Mutator functions are the functions that alter the value of an object. These include constructors and assignment operators.

Accessor functions are the functions that “look at” the value of an object but do not change it. Some functions may both alter an object and return part of itsvalue - we’ll have to wing it a bit with those.

Mutators and Accessors

To test an ADT, divide the public interface into

mutators: functions that alter the value of the object

accessors: functions that “look at” the current value of an object

Occasional functions will fall in both classes

Organizing ADT Tests

The basic procedure for writing an ADT unit test is to

1. Consider each mutator in turn.

2. Write a test that begins by applying that mutator function.

Page 246: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3. Then consider how that mutator will have affected the results of each accessor.

4. Write assertions to test those effects.

Commonly, each mutator will be tested in a separate function.

2.1 Example: Unit Testing of the MailingList Classmailinglist.h +

#ifndef MAILINGLIST_H#define MAILINGLIST_H #include <iostream>#include <string> #include "contact.h" /** A collection of names and addresses */class MailingList { public: MailingList(); MailingList(const MailingList&); ~MailingList(); const MailingList& operator= (const MailingList&); // Add a new contact to the list void addContact (const Contact& contact); // Does the list contain this person? bool contains (const Name&) const; // Find the contact const Contact& getContact (const Name& nm) const; //pre: contains(nm) // Remove one matching contact void removeContact (const Contact&); void removeContact (const Name&); // combine two mailing lists void merge (const MailingList& otherList);

Page 247: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

// How many contacts in list? int size() const; bool operator== (const MailingList& right) const; bool operator< (const MailingList& right) const; private: struct ML_Node { Contact contact; ML_Node* next; ML_Node (const Contact& c, ML_Node* nxt) : contact(c), next(nxt) {} }; ML_Node* first; ML_Node* last; int theSize; // helper functions void clear(); void remove (ML_Node* previous, ML_Node* current); friend std::ostream& operator<< (std::ostream& out, const MailingList& addr); }; // print list, sorted by Contactstd::ostream& operator<< (std::ostream& out, const MailingList& list); #endif

Look at our MailingList class.

Question: What are the mutators? What are the accessors?

Answer: +

Page 248: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The mutators are

the two constructors,

the assignment operator,

addContact,

both removeContact functions, and

merge.

The accessors are

size,

contains

getContact

operator== and operator<

the output operator operator<<

Unit Test Skeleton

Here is the basic skeleton for our test suite.

skeleton.cpp +

#define BOOST_TEST_MODULE MailingList test #include "mailinglist.h" #include <string>#include <sstream>#include <vector> #include <boost/test/included/unit_test.hpp> using namespace std;

Now we start going through the mutators.

Page 249: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.1.1 Testing the Constructors

The first mutators we listed were the two constructors. Let’s start with the simpler of these.

Apply The Mutator

BOOST_AUTO_TEST_CASE ( constructor ) { MailingList ml; ⋮

First we start by applying the mutator.

Apply the Accessors to the Mutated Object

Then we go down the list of accessors and ask what we expect each one to return.

BOOST_AUTO_TEST_CASE ( constructor ) { MailingList ml; BOOST_CHECK_EQUAL (0, ml.size()); BOOST_CHECK (!ml.contains("Jones")); BOOST_CHECK_EQUAL (ml, MailingList()); BOOST_CHECK (!(ml < MailingList())); }

1. It’s pretty clear, for example, that the size() of the list will be 02. contains() would always return false3. The EQUAL test checks the operator==4. We check for consistency of operator<

We can’t check the accessors

getContact

can’t satisfy the pre-condition, and

operator<<

behavior unspecified

Page 250: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Testing the Copy Constructor

testCons1.cpp +

BOOST_FIXTURE_TEST_CASE ( copyConstructor, MailingListTests) { for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); ➀ MailingList ml1 = ml0; // copy constructor ➁ shouldBeEqual(ml0, ml1); ➂ } { // Minimal check for deep copy - changing one should not affect the other MailingList ml0 = generate(2); MailingList ml1 = ml0; // copy constructor ml1.addContact(jones); ➃ BOOST_CHECK_EQUAL (2, ml0.size()); BOOST_CHECK_NE (ml0, ml1); } }

➀ We use the generate-and-check pattern.

➁ Here we invoke the function under test.

➂ The check function - we’ll look at this in a moment

➃ The second half of this is more subtle. I expect that copies are distinct. Once a copy is made, updating one object should not change the other.

A failure suggests that we have done an improper shallow copy.

The Check Function for Copying

shouldBeEqual.cpp +

// The fixture for testing class MailingList.class MailingListTests { public: Contact jones; vector<Contact> contacts; MailingListTests() { ⋮ void shouldBeEqual (const MailingList& ml0, const MailingList& ml1) const

Page 251: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

{ BOOST_CHECK_EQUAL (ml1.size(), ml0.size()); ➀ for (int i = 0; i < ml0.size(); ++i) ➁ { BOOST_CHECK_EQUAL(ml1.contains(contacts[i].getName()), ml0.contains(contacts[i].getName())); if (ml1.contains(contacts[i].getName())) BOOST_CHECK_EQUAL(ml1.getContact(contacts[i].getName()), ml0.getContact(contacts[i].getName())); } BOOST_CHECK_EQUAL (ml0, ml1); ➂ BOOST_CHECK (!(ml0 < ml1)); BOOST_CHECK (!(ml1 < ml0)); ostringstream out0; ➂ out0 << ml0; ostringstream out1; out1 << ml1; BOOST_CHECK_EQUAL (out0.str(), out1.str()); } };

➀ Sizes should be equal

➁ Boths lists should agree as to what they contain.

➂ Relational ops - should be equal and not less/greater

➃ Whatever they print, it should match

2.1.2 Testing the Assignment Operator

testAsst.cpp +

BOOST_FIXTURE_TEST_CASE ( assignment, MailingListTests) { for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml1; MailingList ml2 = (ml1 = ml0); // assignment ➀ shouldBeEqual(ml0, ml1); ➁ shouldBeEqual(ml0, ml2); // assignment returns a value } {

Page 252: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

// Minimal check for deep copy - changing one should not affect the other MailingList ml0 = generate(2); MailingList ml1; ml1 = ml0; // copy constructor ml1.addContact(jones); BOOST_CHECK_EQUAL (2, ml0.size()); BOOST_CHECK_NE (ml0, ml1); } }

Very similar to testing the copy constructor

➀ But remember that assignment operators not only change the value on the left, but also return a copy of the assigned value.

We need to check both.

➁ Fortunately, we can re-use the check function developed for the copy constructor.

2.1.3 Testing addContact

testAdd.cpp +

BOOST_FIXTURE_TEST_CASE (addContact, MailingListTests) { for (unsigned sel = 0; sel < contacts.size(); ++sel) { Contact& toAdd = contacts[sel]; const Name& nameToAdd = toAdd.getName(); for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml (ml0); bool alreadyContained = ml.contains(nameToAdd); ml.addContact (toAdd); BOOST_CHECK (ml.contains(nameToAdd)); BOOST_CHECK_EQUAL (toAdd, ml.getContact(nameToAdd)); if (alreadyContained) { BOOST_CHECK_EQUAL (ml.size(), (int)sz); BOOST_CHECK_EQUAL (ml0, ml); BOOST_CHECK (!(ml0 < ml)); BOOST_CHECK (!(ml < ml0)); } else { BOOST_CHECK_EQUAL (ml.size(), (int)sz+1); BOOST_CHECK_NE (ml0, ml); BOOST_CHECK ((ml0 < ml) || (ml < ml0)); // one must be true

Page 253: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

BOOST_CHECK (!((ml0 < ml) && (ml < ml0))); // ...but not both } ostringstream out; out << ml; BOOST_CHECK_NE (out.str().find(nameToAdd), string::npos); } } }

Similar to version developed earlier, but now we go systematically through all the accessorsNeeded to add checks on relational operators and output operator

2.1.4 And so on…

We continue in this manner until done.

fullTest.cpp +

#define BOOST_TEST_MODULE MailingList test #include "mailinglist.h" #include <string>#include <sstream>#include <vector> #include <boost/test/included/unit_test.hpp>//#define BOOST_TEST_DYN_LINK 1//#include <boost/test/unit_test.hpp> using namespace std; // The fixture for testing class MailingList.class MailingListTests { public: Contact jones; vector<Contact> contacts; MailingListTests() { jones = Contact("Jones", "21 Penn. Ave."); contacts.clear(); contacts.push_back (Contact ("Muffin Man", "Drury Ln.")); contacts.push_back (Contact ("Holmes", "221B Baker St.")); contacts.push_back(jones); contacts.push_back (Contact ("Wolfe", "454 W. 35th St.")); }

Page 254: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

~MailingListTests() { } MailingList generate(int n) const { MailingList m; for (int i = 0; i < n; ++i) m.addContact(contacts[i]); return m; } void shouldBeEqual (const MailingList& ml0, const MailingList& ml1) const { BOOST_CHECK_EQUAL (ml1.size(), ml0.size()); for (int i = 0; i < ml0.size(); ++i) { BOOST_CHECK_EQUAL(ml1.contains(contacts[i].getName()), ml0.contains(contacts[i].getName())); if (ml1.contains(contacts[i].getName())) BOOST_CHECK_EQUAL(ml1.getContact(contacts[i].getName()), ml0.getContact(contacts[i].getName())); } BOOST_CHECK_EQUAL (ml0, ml1); BOOST_CHECK (!(ml0 < ml1)); BOOST_CHECK (!(ml1 < ml0)); ostringstream out0; out0 << ml0; ostringstream out1; out1 << ml1; BOOST_CHECK_EQUAL (out0.str(), out1.str()); } }; BOOST_AUTO_TEST_CASE ( constructor ) { MailingList ml; BOOST_CHECK_EQUAL (0, ml.size()); BOOST_CHECK (!ml.contains("Jones")); BOOST_CHECK_EQUAL (ml, MailingList()); BOOST_CHECK (!(ml < MailingList())); } BOOST_FIXTURE_TEST_CASE ( copyConstructor, MailingListTests) { for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz);

Page 255: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

MailingList ml1 = ml0; // copy constructor shouldBeEqual(ml0, ml1); } { // Minimal check for deep copy - changing one should not affect the other MailingList ml0 = generate(2); MailingList ml1 = ml0; // copy constructor ml1.addContact(jones); BOOST_CHECK_EQUAL (2, ml0.size()); BOOST_CHECK_NE (ml0, ml1); } } BOOST_FIXTURE_TEST_CASE ( assignment, MailingListTests) { for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml1; MailingList ml2 = (ml1 = ml0); // assignment shouldBeEqual(ml0, ml1); shouldBeEqual(ml0, ml2); // assignment returns a value } { // Minimal check for deep copy - changing one should not affect the other MailingList ml0 = generate(2); MailingList ml1; ml1 = ml0; // copy constructor ml1.addContact(jones); BOOST_CHECK_EQUAL (2, ml0.size()); BOOST_CHECK_NE (ml0, ml1); } } BOOST_FIXTURE_TEST_CASE (addContact, MailingListTests) { for (unsigned sel = 0; sel < contacts.size(); ++sel) { Contact& toAdd = contacts[sel]; const Name& nameToAdd = toAdd.getName(); for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml (ml0); bool alreadyContained = ml.contains(nameToAdd); ml.addContact (toAdd); BOOST_CHECK (ml.contains(nameToAdd)); BOOST_CHECK_EQUAL (toAdd, ml.getContact(nameToAdd)); if (alreadyContained) { BOOST_CHECK_EQUAL (ml.size(), (int)sz);

Page 256: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

BOOST_CHECK_EQUAL (ml0, ml); BOOST_CHECK (!(ml0 < ml)); BOOST_CHECK (!(ml < ml0)); } else { BOOST_CHECK_EQUAL (ml.size(), (int)sz+1); BOOST_CHECK_NE (ml0, ml); BOOST_CHECK ((ml0 < ml) || (ml < ml0)); // one must be true BOOST_CHECK (!((ml0 < ml) && (ml < ml0))); // ...but not both } ostringstream out; out << ml; BOOST_CHECK_NE (out.str().find(nameToAdd), string::npos); } } } BOOST_FIXTURE_TEST_CASE (removeContact, MailingListTests) { for (unsigned sel = 0; sel < contacts.size(); ++sel) { Contact& toAdd = contacts[sel]; const Name& nameToAdd = toAdd.getName(); for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml (ml0); bool alreadyContained = ml.contains(nameToAdd); ml.removeContact (toAdd); BOOST_CHECK (!ml.contains(nameToAdd)); if (!alreadyContained) { BOOST_CHECK_EQUAL (ml.size(), (int)sz); BOOST_CHECK_EQUAL (ml0, ml); BOOST_CHECK (!(ml0 < ml)); BOOST_CHECK (!(ml < ml0)); } else { BOOST_CHECK_EQUAL (ml.size(), (int)sz-1); BOOST_CHECK_NE (ml0, ml); BOOST_CHECK ((ml0 < ml) || (ml < ml0)); // one must be true BOOST_CHECK (!((ml0 < ml) && (ml < ml0))); // ...but not both } ostringstream out; out << ml; string outs = out.str(); BOOST_CHECK_EQUAL (outs.find(nameToAdd), string::npos); } }

Page 257: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

} BOOST_FIXTURE_TEST_CASE (removeContactByName, MailingListTests) { for (unsigned sel = 0; sel < contacts.size(); ++sel) { Contact& toAdd = contacts[sel]; const Name& nameToAdd = toAdd.getName(); for (unsigned sz = 0; sz < contacts.size(); ++sz) { MailingList ml0 = generate(sz); MailingList ml (ml0); bool alreadyContained = ml.contains(nameToAdd); ml.removeContact (nameToAdd); BOOST_CHECK (!ml.contains(nameToAdd)); if (!alreadyContained) { BOOST_CHECK_EQUAL (ml.size(), (int)sz); BOOST_CHECK_EQUAL (ml0, ml); BOOST_CHECK (!(ml0 < ml)); BOOST_CHECK (!(ml < ml0)); } else { BOOST_CHECK_EQUAL (ml.size(), (int)sz-1); BOOST_CHECK_NE (ml0, ml); BOOST_CHECK ((ml0 < ml) || (ml < ml0)); // one must be true BOOST_CHECK (!((ml0 < ml) && (ml < ml0))); // ...but not both } ostringstream out; out << ml; BOOST_CHECK_EQUAL (out.str().find(nameToAdd), string::npos); } } } BOOST_FIXTURE_TEST_CASE ( merging, MailingListTests) { MailingList ml0; ml0.addContact(contacts[0]); ml0.addContact(contacts[1]); ml0.addContact(contacts[2]); MailingList ml1; ml1.addContact(contacts[2]); ml1.addContact(contacts[3]); ml1.merge(ml0); shouldBeEqual(ml1, generate(4)); }

Page 258: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Yes, BTW, I did discover quite a few bugs in my MailingList code while putting this together.

2.2 Testing for Pointer/Memory FaultsIn our example, we did not write explicit tests for the destructor. Partly that’s because the destructor is already being invoked a lot - every time we exit afunction or a {…} statement block that declares a local variable. So we have some good reason to hope that the destructor has been well exercised already.

Also, most of the effects of a destructor are hard to see directly. How do you check to see if memory has been successfully deleted?

Most destructors simply delete pointers, and pointer issues are particularly difficult to test and debug.

One way that pointer/memory use can be tested is to employ specialized tools that replace the system functions for allocating and deallocating memory(alloc and free) with special versions that

keep track of all blocks of memory that have been allocated,

whether those blocks have been freed,

whether any block has been freed more than once, etc.

Tools for Testing Pointer/Memory Faults

Purify is a well known commercial package for this purpose, but is not cheap.

I have had good results with a free tool called LeakTracer.

2.3 Case Study 1: Unit Test of NumericLiteralOne of the stories in our spreadsheet example involves numeric literals, the component of an expression that represents a constant numeric value like “3.14159”or “42”.

As an API user I would like to add a numeric literal to a cell in a spreadsheet.

Numeric literals are a kind of Expression, a central idea in the spreadsheet. This story offers an opportunity for a look at a realistic set of tests.

Page 259: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.3.1 Expressions

Expression.java +

package edu.odu.cs.espreadsheet.expressions; import java.io.StringReader; import edu.odu.cs.espreadsheet.ExpressionParseError; import edu.odu.cs.espreadsheet.Spreadsheet; import edu.odu.cs.espreadsheet.values.Value; /** * Expressions can be thought of as trees. Each non-leaf node of the tree * contains an operator, and the children of that node are the subexpressions * (operands) that the operator operates upon. Constants, cell references, * and the like form the leaves of the tree. * * For example, the expression (a2 + 2) * c26 is equivalent to the tree: * * * * / \ * + c26 * / \ * a2 2 * * @author zeil * */public abstract class Expression implements Cloneable { /** * How many operands does this expression node have? * * @return # of operands required by this operator */ public abstract int arity(); /** * Get the k_th operand * @param k operand number * @return k_th operand if 0 < k < arity() * @throws IndexOutOfBoundsException if k is outside of those bounds */ public abstract Expression operand(int k) throws IndexOutOfBoundsException;

Page 260: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

/** * Evaluate this expression, using the provided spreadsheet to resolve * any cell referneces. * * @param usingSheet spreadsheet form which to obtain values of * cells referenced by this expression * * @return value of the expression or null if the cell is empty */ public abstract Value evaluate(Spreadsheet usingSheet); /** * Copy this expression (deep copy), altering any cell references * by the indicated offsets except where the row or column is "fixed" * by a preceding $. E.g., if e is 2*D4+C$2/$A$1, then * e.copy(1,2) is 2*E6+D$2/$A$1, e.copy(-1,4) is 2*C8+B$2/$A$1 * * @param colOffset number of columns to offset this copy * @param rowOffset number of rows to offset this copy * @return a copy of this expression, suitable for placing into * a cell (ColOffSet,rowOffset) away from its current position. * */ public abstract Expression clone (int colOffset, int rowOffset); /** * Copy this expression. */ @Override public Expression clone () { return clone(0,0); } /** * Attempt to convert the given string into an expression. * @param in * @return */ public static Expression parse (String in) throws ExpressionParseError { try { parser p = new parser(new ExpressionScanner(new StringReader(in))); Expression expr = (Expression)p.parse().value; return expr;

Page 261: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

} catch (Exception ex) { throw new ExpressionParseError("Cannnot parse " + in); } } @Override public String toString () { ⋮ } @Override public abstract boolean equals (Object obj); @Override public abstract int hashCode (); // The following control how the expression gets printed by // the default implementation of toString /** * If true, print in inline form. * If false, print as functionName(comma-separated-list). * * @return indication of whether to print in inline form. * */ public abstract boolean isInline(); /** * Parentheses are placed around an expression whenever its precedence * is lower than the precedence of an operator (expression) applied to it. * E.g., * has higher precedence than +, so we print 3*(a1+1) but not * (3*a1)+1 * * @return precedence of this operator */ public abstract int precedence(); /** * Returns the name of the operator for printing purposes. * For constants/literals, this is the string version of the constant value. * * @return the name of the operator for printing purposes. */

Page 262: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public abstract String getOperator(); }

A lot of this design was lifted from an earlier project of mine.

Expression is an abstract class – we never expect to see any actual objects of this type.

But we will have lots of interesting subclasses (one per operator) that will have “real” instances.

2.3.2 Numeric Literals

The NumericLiteral class is a subclass of Expression and needs to supply function bodies for all of the unimplemented functions declared in Expression.

NumericLiteral.java +

package edu.odu.cs.espreadsheet.expressions; import edu.odu.cs.espreadsheet.Spreadsheet; import edu.odu.cs.espreadsheet.values.NumericValue; import edu.odu.cs.espreadsheet.values.Value; /** * This class represents numeric constants appearing within an expression. * * @author zeil * */publicclass NumericLiteral extends Expression { ⋮ /** * Create a default numeric literal. Equivalent to NumericLiteral("0"); */ public NumericLiteral () { ⋮ } public NumericLiteral (String lit) { ⋮ }

Page 263: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

/** * How many operands does this expression node have? * * @return # of operands required by this operator */ public int arity() {return 0;} /** * Get the k_th operand * @param k operand number * @return k_th operand if 0 < k < arity() * @throws IndexOutOfBoundsException if k is outside of those bounds */ public Expression operand(int k) { ⋮ } /** * Evaluate this expression, using the provided spreadsheet to resolve * any cell references. * * @param usingSheet spreadsheet form which to obtain values of * cells referenced by this expression * * @return value of the expression or null if the cell is empty */ public Value evaluate(Spreadsheet s) { ⋮ } /** * Copy this expression (deep copy), altering any cell references * by the indicated offsets except where the row or column is "fixed" * by a preceding $. E.g., if e is 2*D4+C$2/$A$1, then * e.copy(1,2) is 2*E6+D$2/$A$1, e.copy(-1,4) is 2*C8+B$2/$A$1 * * @param colOffset number of columns to offset this copy * @param rowOffset number of rows to offset this copy * @return a copy of this expression, suitable for placing into * a cell (ColOffSet,rowOffset) away from its current position. * */ @Override public NumericLiteral clone (int colOffset, int rowOffset) {

Page 264: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

⋮ } // The following control how the expression gets printed by // the default implementation of put(ostream&) /** * Attempt to convert the given string into an expression. * @param in * @return */ public boolean isInline() {return true;} /** * If true, print in inline form. * If false, print as functionName(comma-separated-list). * * @return indication of whether to print in inline form. * */ public int precedence() {return 1000;} /** * Returns the name of the operator for printing purposes. * For constants/literals, this is the string version of the constant value. * * @return the name of the operator for printing purposes. */ public String getOperator() {return literal;} @Override public boolean equals(Object obj) { ⋮ } @Override public int hashCode() { ⋮ } }

I’m not showing the actual implementaiton (function bodies) here because

Page 265: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

It’s not relevant to the design of the tests.In fact, as we’ll see very shortly, I usually write the tests before I implement the ADT. So, in practice, those function bodies would be empty when I dothis.

2.3.3 Writing the Unit tests

NumericLiteral desperately needs a good set of unit test cases because we need to be sure that we have covered all of the various input format possibilities:

TestNumericLiteral.java +

/** * */package edu.odu.cs.espreadsheet.expressions; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; import edu.odu.cs.espreadsheet.ExpressionParseError; import edu.odu.cs.espreadsheet.Spreadsheet; /** * @author zeil * */public class TestNumericLiteral { public final NumericLiteral nl0 = new NumericLiteral("2.345"); public final Spreadsheet ss = new Spreadsheet(); /** * Test method for {@link edu.odu.cs.espreadsheet.expressions.NumericLiteral#NumericLiteral()}. */ @Test public final void testNumericLiteral() { NumericLiteral nl = new NumericLiteral(); ➀ assertEquals(0, nl.arity()); ➁ try { nl.operand(0); fail("Expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException ex) { // OK }

Page 266: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

assertEquals (0.0, nl.evaluate(ss).toDouble(), 1.0E-10); assertEquals ("0", nl.toString()); assertEquals (true, nl.isInline()); assertTrue (nl.precedence() > 100); assertEquals ("0", nl.getOperator()); assertFalse (nl0.equals(nl)); } /** * Test method for {@link edu.odu.cs.espreadsheet.expressions.NumericLiteral#NumericLiteral(java.lang.String)}. */ @Test public final void testNumericLiteralString() { NumericLiteral nl = new NumericLiteral("2.3450"); assertEquals(0, nl.arity()); try { nl.operand(0); fail("Expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException ex) { // OK } assertEquals (2.345, nl.evaluate(ss).toDouble(), 1.0E-10); assertEquals ("2.3450", nl.toString()); assertEquals (true, nl.isInline()); assertTrue (nl.precedence() > 100); assertEquals ("2.3450", nl.getOperator()); assertFalse (nl0.equals(nl)); } /** * Test method for {@link edu.odu.cs.espreadsheet.expressions.NumericLiteral#clone(int, int)}. */ @Test public final void testCloneIntInt() { NumericLiteral nl = nl0.clone(1,1); assertEquals(0, nl.arity()); try { nl.operand(0); fail("Expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException ex) { // OK } assertEquals (nl0.evaluate(ss), nl.evaluate(ss)); assertEquals (nl0.toString(), nl.toString()); assertEquals (nl0.isInline(), nl.isInline()); assertEquals (nl0.precedence(), nl.precedence()); assertEquals (nl0.getOperator(), nl.getOperator()); assertEquals (nl0, nl); }

Page 267: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

/** * Test method for {@link edu.odu.cs.espreadsheet.expressions.Expression#clone()}. */ @Test public final void testClone() { NumericLiteral nl = (NumericLiteral)nl0.clone(); assertEquals(0, nl.arity()); try { nl.operand(0); fail("Expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException ex) { // OK } assertEquals (nl0.evaluate(ss), nl.evaluate(ss)); assertEquals (nl0.toString(), nl.toString()); assertEquals (nl0.isInline(), nl.isInline()); assertEquals (nl0.precedence(), nl.precedence()); assertEquals (nl0.getOperator(), nl.getOperator()); assertEquals (nl0, nl); } /** * Test method for {@link edu.odu.cs.espreadsheet.expressions.Expression#parse(java.lang.String)}. * @throws ExpressionParseError */ @Test public final void testNumericParse() throws ExpressionParseError { String input = "12.34"; ➂ Expression e = Expression.parse(input); assertTrue (e instanceof NumericLiteral); assertEquals (new NumericLiteral(input), e); input = "1.2E25"; e = Expression.parse(input); assertTrue (e instanceof NumericLiteral); NumericLiteral nl = (NumericLiteral)e; assertEquals (1.2E25, new Double(nl.getOperator()).doubleValue(), 1.0E20); input = "1.2E-5"; e = Expression.parse(input); assertTrue (e instanceof NumericLiteral); nl = (NumericLiteral)e; assertEquals (1.2E-5, new Double(nl.getOperator()).doubleValue(), 1.0E-10); } }

➀ These tests are good examples of our mutator/accessor approach to devising unit tests.

Page 268: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The mutators for this class are the two constructors and the two clone functions.

The accessors are arity(), operand(i), evaluate(ss), isInLine(), precedence(), getOperator(), ’equals(…), hashCode(), andtoString()`.

In this test we invoke one of the mutators (a constructor)

➁ Then we run through each of the accessors in turn.

This pattern is repeated for each of the mutators.

➂ A more subtle “mutator”: Expression has a static function for parsing strings. It is, more or less, a mutator for all subclasses of expression. So we testit here as well.

Could have made this part of a unit test for Expression, but that would have led to a single test that had to know about every subclass ofExpression, which would have grown quickly unwieldy.

2.4 Is this Overkill?Many, perhaps most, ADTs provide a small number of operations that manipulate the data in a non-trivial fasion, and a lage number of get/set attribute functionsthat, conceptually at least, simply store and retrieve a private data member.

For example, suppose we wanted to test the following ADT:

Address.java +

package mailinglist; /** * A contact is a name and address. * <p> * For the purpose of this example, I have simplified matters * a bit by making both of these components simple strings. * In practice, we would expect Address, at least, to be a * more structured type. * * @author zeil * */public class Address implements Cloneable { private String name; private String streetAddress; private String city; private String state; private String zipCode;

Page 269: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

/** * Create an address with all empty fields. * */ public Address () { name = ""; streetAddress = ""; city = ""; state = ""; zipCode = ""; } /** * Create an address. */ public Address (String nm, String streetAddr, String city, String state, String zip) { name = nm; streetAddress = streetAddr; this.city = city; this.state = state; zipCode = zip; } /** * @return the theName */ public String getName() { return name; } /** * @param theName the theName to set */ public void setName(String theName) { this.name = theName; } /** * @return the streetAddress */ public String getStreetAddress() { return streetAddress; } /**

Page 270: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

* @param streetAddress the streetAddress to set */ public void setStreetAddress(String streetAddress) { this.streetAddress = streetAddress; } /** * @return the city */ public String getCity() { return city; } /** * @param city the city to set */ public void setCity(String city) { this.city = city; } /** * @return the state */ public String getState() { return state; } /** * @param state the state to set */ public void setState(String state) { this.state = state; } /** * @return the zipCode */ public String getZipCode() { return zipCode; } /** * @param zipCode the zipCode to set */ public void setZipCode(String zipCode) { this.zipCode = zipCode; } /** * True if the names and addresses are equal

Page 271: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

*/ public boolean equals (Object right) { Address r = (Address)right; return name.equals(r.name) && streetAddress.equals(r.streetAddress) && city.equals(r.city) && state.equals(r.state) && zipCode.equals(r.zipCode); } public int hashCode () { return name.hashCode() + 3 * streetAddress.hashCode() + 5 * city.hashCode() + 7 * state.hashCode() + 11 * zipCode.hashCode(); } public String toString() { return name + ": " + streetAddress + ": " + city + ", " + state + " " + zipCode; } public Object clone() { return new Address(name, streetAddress, city, state, zipCode); } }

You can see that, in this case, the bulk of the operations are simple gets and sets. There are a few operations that work, in some sense, on the whole ADT,mainly for the purpose of output and comparisons.

If we were to test this, we would identify the mutators (the two constructors, the five set… functions, and the clone function) and accessors (the five get…functions and the toString, equals, and hashCode functions). Then we would create a test function for each mutator. For example, for the setCity function,we might write:

public class TestAddress { final private String name0 = "John Doe"; final private String street0 = "221B Baker St."; final private String city0 = "Podunk"; final private String state0 = "IL"; final private String zip0 = "01010";

Page 272: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

⋮ @Testpublic final void testSetCity() { String city1 = "Norfolk"; ➀ Address addr0 = new Address(name0, street0, city0, state0, zip0); Address addr1 = new Address(name0, street0, city0, state0, zip0); addr1.setCity(city1); ➁ assertEquals (name0, addr1.getName()); ➂ assertEquals (street0, addr1.getStreetAddress()); assertEquals (city1, addr1.getCity()); assertEquals (state0, addr1.getState()); assertEquals (zip0, addr1.getZipCode()); assertFalse (addr1.equals(addr0)); assertTrue (addr1.toString().contains(city1)); }

This follows a pattern that should be increasingly familiar:

➀ Set up the data values that we will need.➁ Invoke the mutator being tested.➂ Evaluate and test each of the accessor functions on the mutated ADT value.

You can see that four out of the first five assertions actually assert that this value was unaffected by the mutator. Some students look at this and wonder why webother. Isn’t that a lot of wasted code? It doesn’t seem to really be relevant to the mutator function (setCity) that we are testing in this function. And when youconsider that there will be similar “waste” in each of the other functions for testing the other mutator functions, this can seem excessive.

But there are a number of reasons why these “does not change” assertions are worth performing:

Our intuition is that a working implementation of setCity won’t have any effect on the street address, zip code, etc.. But, if we knew that the code wasworking, we wouldn’t be testing it!

True story: I often write an ADT like this by typing out the first pair of get and set functions (e.g., getName and setName), then copying and pasting thosemultiple times, and then using my editor’s search-and-replace function to alter the attribute names in the subsequent pairs.

On more than one occasion, I have forgotten to change the name of the data member being retrieved by a get/set pair, winding up with a bug somethinglike like this:

public String getCity() { return name; }

Page 273: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public void setCity(String city) { this.name = name; }

This bug was detected by the "getName() does not change when setCity is called) assertion in the testSetCity test function.

Our intuition that the behavior of “getCity” has no bearing on the testing of “setCity” is based on a misunderstanding of what the test functions aredoing. Although we allocate one test function per mutator, each such function is not merely testing its associated mutator. It is testing both that mutatorand all the accessors.

The collected tests of all of accessor functions are distributed over the entire set of test functions. If we eliminated all checks of an accessor getX but theone in the testSetX function, that accessor would wind up being woefully under-tested.

On the other hand, what would be excessive would be to devote separate test functions to both mutators and accessors (depeite the fact that this is whatEclipse volunteers to do if you use its “New … Junit Test Case” helper). The only way to test an accessor is to use some mutator to set the ADT value,and we’re already doing that the the test functions for mutators.

Our intuition that the behavior of a getX accessor is independent of a setY mutator for a different attribute is colored by our assumption that these get/setfunctions are doing nothing but retrieving simple data members.

But that’s not always the case, and, even if that’s how the ADT is implemented now, it might not be implemented that way in the future.

If the program is distributed, so that address values are actually being transferred over the network, we will likely receive and sometimes storeaddresses in a serialized form, essentially a single string.

In that case, we would need to tease out the individual field values like cities, states, etc., and the possibility of “cross-talk” among the fields due tobuggy code becomes significant.

Similar serialized forms are common if we have a program that mixes code written in different programming langauges.

A similar problem can arise if the actual Address values need to be stored in and retrieved from a database. Perhaps the databse is set up tocombine, for example, the city and state in a single field.

These are Black-box tests, and we want them to remain valid even if the implementation changes.

In general, it’s always a bit dangerous to argue that tests are unnecessary based on our intuition about how the code will behave when it runs correctly. Ourchoice of tests really have to be more informed by the possibilities of how the code might misbehave when it has bugs.

Furthermore, these “extra” assertions are not really all that oppressive. Most of them, written once, can be copied and pasted into the next test function. Forexample, the testSetState function could be:

@Testpublic final void testSetState() {

Page 274: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

String state1 = "VA"; Address addr0 = new Address(name0, street0, city0, state0, zip0); Address addr1 = new Address(name0, street0, city0, state0, zip0); addr1.setState(state1); assertEquals (name0, addr1.getName()); assertEquals (street0, addr1.getStreetAddress()); assertEquals (city0, addr1.getCity()); assertEquals (state1, addr1.getState()); assertEquals (zip0, addr1.getZipCode()); assertFalse (addr1.equals(addr0)); assertTrue (addr1.toString().contains(state1)); }

The highlighted portions are the only changes from the earlier testSetCity function.

A final comment on the “Is this excessive?” question:

These tests are not, by any measure, a perfect or full set of tests that will detect all bugs. Having done this first pass, we would still want to look at thetests from the perspective of good black-box testing, possibly adjusting the vlues used for inputs or maybe doing more than one invocation of somemutators.

That said, this is still more testing and better testing than most programmers perform if they don’t let themselves by guided by some approach, like thismutator/accessor approach, for being thorough and systematic in their test design.

Finally, many students’ perception of what makes testing difficult and time-consuming is rooted in the practice of running tests “manually” and inspectingall outputs by eye. No wonder, then, that even running a small test set seems like drudgery.

But we’ve just automated the checking part of testing.

And with Eclipse and other IDE’s we can run those tests with single mouse action. And, shortly, we’ll integrate the tests into our automated build processso that launching tests does not even require that small effort.

3 Be Independent:A true unit test should not depend on other modules of the program

The *unit frameworks we have looked at provide drivers.But scaffolding can also involve stubs.

Which are often harder to write

Page 275: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

We could

Wait until integration test, or

Prepare stubs for unit testing and accept that they can only be rough approximations, or

Create stubs for unit testing and replace them later when the lower-level modules are ready.

Is there a virtue to independence?

Integration tests are not independent.

Can lead to slower testing.Can complicate debuggingBut are certainly more realistic than unit tests with simple stubs

Increasingly, *unit frameworks are providing support for stubbing.

We’ll cover this in the next lesson on mock objects.

Page 276: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Test-Driven DevelopmentSteven J Zeil

Last modified: Jan 7, 2020

Contents:1 Test-First Development

1.1 Debugging: How Can You Fix What You Can’t See?1.2 Test-Writing as a Design Activity1.3 The Cycle of Unit Test Failures

2 TFD during Incremental Development2.1 Case Study: TFD of a Spreadsheet Story

3 Test-Driven Development3.1 The “Three Rules of TDD”3.2 Example of TDD

Abstract

Test-Driven Development treats unit testing as an integral part of the design and implementation process. Often summarized as “test first, code after”, TDD isactually a recognition that in writing tests, we are

exploring the API design, andanticipating design issues, as well asproviding for effortless validation of our upcoming implementation.

1 Test-First DevelopmentWith our new knowledge of unit-testing frameworks, ideally, we have made it easier to write self-checking unit tests than to write the actual code to be tested.

We encourage an approach of writing the tests before writing the code.

1.1 Debugging: How Can You Fix What You Can’t See?The test-first philosophy is easiest to understand in a maintenance/debugging context.

Page 277: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Before attempting to debug, write a test that reproduces the failure.

How else will you know when you’ve fixed it?

From a practical point of view, debugging generally involves running the buggy input, over and over, while you add debugging output or step throughwith a debugger.

You want that to be as easy as possible.Doing this at the unit level, instead of in the context of the entire system, is often a dramatically better use of your time and effort.

1.2 Test-Writing as a Design ActivityEvery few years, software designers rediscover the principle of writing tests before implementing code.

Agile and TDD (Test-Driven Development) are just the latest in this long chain.

Writing tests while “fresh” yields better tests than when they are done as an afterthought.

Thinking about boundary and special values tests helps clarify the software design

Reduces the number of eventual faults actually introduced

Encourages designing for testability

Making sure that the interface provides the “hooks” you need to do testing in the first place.

1.2.1 Tests are Examples

“If it’s hard to write a test, it’s a signal that you have a design problem, not a testing problem. Loosely coupled, highly cohesive code is easy totest.” – Kent Beck

In writing a test, you are actually writing sample code of how the unit’s interface can be used.

Valuable as documentation

It’s very common when writing tests to discover that the interface is incorrect or inadequate.

Interface may not have parameters to supply needed data, or may have the wrong parameters.Functions may be missing that would manipulate the ADT state.Functions may be missing that owuld allow us to examine the ADT state to see the effects of a manipulation

Page 278: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The very act of trying to write black-box tests becomes itself an exercise in validation of the interface design!

1.3 The Cycle of Unit Test Failures

Here you can see a plot of test cases on the vertical axis versus time (actually,commits to the version control system) on the horizontal axis during a project onwhich I practiced TFD.

Tests passed are shown in blue and failed tests are shown in red.

Notice the repeated pattern:

There are multiple sudden rises in the number of tests failed.

These are matched by a simultaneous and equal increase in the totalnumber of tests. So what we are seeing is the additon of new tests that we, initially, fail.That’s because in TFD we write tests first for code that we have not yet developed. Naturally, we fail those tests.

Each such rise is followed by an eventual decrease in the number of failed tests while the total number of tests stays constant (so the blue area grows).

That’s because, after developing the new tests, we started working on implementing the new funcitonality, eventually passing most of those newtests.

There remains, through most of the project, a base set of red tests that we never quite pass.

That’s because I am often adding both unit and integration tests.Unit tests will test our modified ADT(s) in isolation from the rest of the system. They can be passed as soon as we finish the ADT modifications.Integration tests test the modified ADT(s) together with other portions of the system. We can’t pass these until later in the project when those otherportions of hte system have actually been implemented.

You can see, near the end of the project time, that the “stubborn” base of failed tests is finally starting to decrease.

2 TFD during Incremental DevelopmentMy stereotypical division of a story into tasks is typically

1. Create/modify the API to describe a new desired behavior.2. Write the unit tests.3. Implement the new behavior.4. Integrate and commit changes.

Page 279: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Compare this to the steps of TDD, above, and you can see that they are compatible.

2.1 Case Study: TFD of a Spreadsheet StoryHere are some short videos illustrating my application of task 1 and task 2 of a story for the Embeddable Spreadsheet project.

3 Test-Driven DevelopmentTest-Driven Development (TDD) is a stronger form of Test-First Development.

In TDD, we repeatedly:

1. Write an automated test case for a new desired behavior.

This case must, initially, fail.Not compiling counts as “failing”.

2. Write just enough new code to pass the test.

3. Refactor the code to make it acceptable quality.

This ties in very nicely with some of our previous discussion of incremental development. In particular, compare to the way we break stories into tasks.

3.1 The “Three Rules of TDD”From Robert Martin

Over the years I have come to describe Test Driven Development in terms of three simple rules. They are:

1. You are not allowed to write any production code unless it is to make a failing unit test pass.2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

You must begin by writing a unit test for the functionality that you intend to write. But by rule 2, you can’t write very much of that unit test. Assoon as the unit test code fails to compile, or fails an assertion, you must stop and write production code. But by rule 3 you can only write theproduction code that makes the test compile or pass, and no more.

If you think about this you will realize that you simply cannot write very much code at all without compiling and executing something. Indeed, thisis really the point. In everything we do, whether writing tests, writing production code, or refactoring, we keep the system executing at all times.

Page 280: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The time between running tests is on the order of seconds, or minutes. Even 10 minutes is too long.

Less time spent debugging: the code worked just a minute ago.Every hour you are adding multiple tests: tests accumulate quicklyLess resistance to cleaning up bad/ugly code: you won’t break things (badly). You have the tests!

3.2 Example of TDDThe Bowling Game Kata (from Martin.)

Page 281: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Stubs and MockingSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Stubs2 Mock Objects

2.1 Google Mock (C++)2.2 JMockit (Java)

3 Case Studies3.1 Example 1 (Spreadsheet CLI)3.2 Example 2: Adding Numeric Literals to the Spreadsheet

4 Are Mock Frameworks Useful?

Abstract

The *Unit frameworks that we have looked at provide powerful support for writing test drivers. But we know that scaffolding comes in two forms: drivers andstubs.

In this lesson, we look at a modern approach to stubs, mock objects. Suppose that we are testing class A and that A calls functions from a class B. A mock objectfor B is interface-compatible with B, but combines a simple (possibly automatically-generated) implementation together with test instrumentation to help usdetermine if A is calling upon B properly during testing.

1 StubsThe Lowly Stub

Most of what *Unit does is to provide a standard, convenient framework for writing test drivers.

But unit testing often requires stubs as well

supplying values/operations to the module under testprocessing outputs from the module under test

We can avoid stubs by doing bottom-up integration

Page 282: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

reduces independence of test suitesrestricts development options

Where ADTs and Stubs Meet

In some ways, ADTs and OOP make it easier to do stubs.

A mock object is an object whose interface emulates a “real” class for testing purposes.

Mock objects may …

be simpler than the real thing

stand-in for classes not yet implemented

decouple test suites

offer mechanisms for data collection, thus improving testability

Example: Mailing List

In our MailingList tests, we relied on a Contact class.

Here is the real interface for Contact:

contactnmad.h +

#ifndef CONTACT_H#define CONTACT_H #include <iostream>#include <string> #include "name.h"#include "address.h" class Contact { Name theName; Address theAddress; public: Contact (Name nm, Address addr) : theName(nm), theAddress(addr) {}

Page 283: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Name getName() const {return theName;} void setName (Name nm) {theName= nm;} Address getAddress() const {return theAddress;} void setAddress (Address addr) {theAddress = addr;} bool operator== (const Contact& right) const { return theName == right.theName && theAddress == right.theAddress; } bool operator< (const Contact& right) const { return (theName < right.theName) || (theName == right.theName && theAddress < right.theAddress); } }; inlinestd::ostream& operator<< (std::ostream& out, const Contact& c) { out << c.getName() << " @ " << c.getAddress(); return out; } #endif #ifndef NAME_H#define NAME_H #include <iostream>#include <string> struct Name { std::string last; std::string first; std::string middle; Name (std::string lastName, std::string firstName, std::string middleName) : last(lastName), first(firstName), middle(middleName) {}

Page 284: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

bool operator== (const Name& right) const; bool operator< (const Name& right) const; }; std::ostream& operator<< (std::ostream& out, const Name& addr); #endif #ifndef ADDRESS_H#define ADDRESS_H #include <iostream>#include <string> struct Address { std::string street1; std::string street2; std::string city; std::string state; std::string zipcode; Address (std::string str1, std::string str2, std::string cty, std::string stte, std::string zip) : street1(str1), street2(str2), city(cty), state(stte), zipcode(zip) {} bool operator== (const Address& right) const; bool operator< (const Address& right) const; }; std::ostream& operator<< (std::ostream& out, const Address& addr); #endif

What Do We Need for the MailingList Test?

But in our tests, the only things we needed to do with contacts was

Page 285: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

create them with known names

copy/assign them

getName()

compare them, ordering by name

A Mock Contact

So we made do with a simpler interface that

made it easier to create and check contacts during testing

but would still compile with the existing MailingList code

contact.h +

#ifndef CONTACT_H#define CONTACT_H #include <iostream>#include <string> typedef std::string Name; typedef std::string Address; class Contact { Name theName; Address theAddress; public: Contact() {} Contact (Name nm, Address addr) : theName(nm), theAddress(addr) {} Name getName() const {return theName;} void setName (Name nm) {theName= nm;} Address getAddress() const {return theAddress;} void setAddress (Address addr) {theAddress = addr;} bool operator== (const Contact& right) const

Page 286: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

{ return theName == right.theName && theAddress == right.theAddress; } bool operator< (const Contact& right) const { return (theName < right.theName) || (theName == right.theName && theAddress < right.theAddress); } }; inlinestd::ostream& operator<< (std::ostream& out, const Contact& c) { out << c.getName() << " @ " << c.getAddress(); return out; } #endif

Replacing the Name and Address classes by simple strings.

2 Mock ObjectsObject-oriented languages make it easier to create some mock objects

Declare the mock as a subclass of the real interface

Override the functions as desired

Example: for an application that drew graphics using the Java java.awt.Graphics API, I created the following as a mock class:

GraphicsStub.java +

package Pictures; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.Shape;

Page 287: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

import java.awt.image.ImageObserver; import java.text.AttributedCharacterIterator; /** * Special version of Graphics for testing that simply writes all graphics requests to * a string. * * @author zeil * */public class GraphicsStub extends Graphics { private StringBuffer log; public GraphicsStub() { log = new StringBuffer(); } public void clearRect(int arg0, int arg1, int arg2, int arg3) { entering("clearRect", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); } public void clipRect(int arg0, int arg1, int arg2, int arg3) { entering("clipRect", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); } public void copyArea(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { entering("copyArea", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5); } public Graphics create() { entering("create", ""); return new GraphicsStub(); } public void dispose() { entering("dispose", ""); } public void drawArc(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { entering("drawArc", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5); } public boolean drawImage(Image arg0, int arg1, int arg2, ImageObserver arg3) {

Page 288: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

entering("drawImage", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); return true; } public boolean drawImage(Image arg0, int arg1, int arg2, Color arg3, ImageObserver arg4) { entering("drawImage", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); return true; } public boolean drawImage(Image arg0, int arg1, int arg2, int arg3, int arg4, ImageObserver arg5) { entering("drawImage", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4); return true; } public boolean drawImage(Image arg0, int arg1, int arg2, int arg3, int arg4, Color arg5, ImageObserver arg6) { entering("drawImage", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5); return true; } public boolean drawImage(Image arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, ImageObserver arg9) { entering("drawImage", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5 + arg6 + ":" + arg7 + ":" + arg8); return true; } public boolean drawImage(Image arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, Color arg9, ImageObserver arg10) { entering("drawImage", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5 + arg6 + ":" + arg7 + ":" + arg8 + ":" + arg9); return true; } public void drawLine(int arg0, int arg1, int arg2, int arg3) { entering("drawLine", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); } public void drawOval(int arg0, int arg1, int arg2, int arg3) { entering("drawOval",

Page 289: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

"" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); } public void drawPolygon(int[] arg0, int[] arg1, int arg2) { entering("drawPolygon", "" + arg0 + ":" + arg1 + ":" + arg2); } public void drawPolyline(int[] arg0, int[] arg1, int arg2) { entering("drawPolyline", "" + arg0 + ":" + arg1 + ":" + arg2); } public void drawRoundRect(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { entering("drawRoundRect", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5); } public void drawString(String arg0, int arg1, int arg2) { entering("drawString", "" + arg0 + ":" + arg1 + ":" + arg2); } public void drawString(AttributedCharacterIterator arg0, int arg1, int arg2) { entering("drawString", "" + arg0 + ":" + arg1 + ":" + arg2); } public void fillArc(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { entering("fillArc", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5); } public void fillOval(int arg0, int arg1, int arg2, int arg3) { entering("fillOval", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); } public void fillPolygon(int[] arg0, int[] arg1, int arg2) { entering("fillPolygon", "" + arg0 + ":" + arg1 + ":" + arg2); } public void fillRect(int arg0, int arg1, int arg2, int arg3) { entering("fillRect", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); }

Page 290: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public void fillRoundRect(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5) { entering("fillRoundRect", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3 + ":" + arg4 + ":" + arg5); } private Shape clip = null; public Shape getClip() { return clip; } public Rectangle getClipBounds() { return null; } private Color color; public Color getColor() { return color; } public Font getFont() { return null; } public FontMetrics getFontMetrics(Font arg0) { return null; } public void setClip(Shape arg0) { entering("setClip", "" + arg0); clip = arg0; } public void setClip(int arg0, int arg1, int arg2, int arg3) { entering("setClip", "" + arg0 + ":" + arg1 + ":" + arg2 + ":" + arg3); } public void setColor(Color arg0) { entering("setColor", "" + arg0); color = arg0; } public void setFont(Font arg0) { entering("setFont", "" + arg0); }

Page 291: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

public void setPaintMode() { entering("setPaintMode", ""); } public void setXORMode(Color arg0) { entering("setXORMode", "" + arg0); } public void translate(int arg0, int arg1) { entering("translate", "" + arg0 + ":" + arg1); } public String toString() { return log.toString(); } public void clear() { log = new StringBuffer(); } private void entering(String functionName, String args) { log.append(functionName); log.append(": "); log.append(args); log.append("\n"); } }

It basically writes each successive graphics call into a string, that can later be examined by unit test cases.

OO Mock Example

Here is a test using that mock:

linesegTest.java +

package PictureTests; import java.awt.Color; import java.awt.Point; import java.lang.reflect.Method; import java.util.Scanner;

Page 292: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

import junit.framework.*; import junit.textui.TestRunner; import Pictures.GraphicsStub; import Pictures.LineSegment; import Pictures.Shape; /** * Test of the LineSegment class */public class LineSegmentTest extends TestCase { ⋮ public void testPlot() { Point p1 = new Point(22, 341); Point p2 = new Point(104, 106); LineSegment ls = new LineSegment(p1, p2, Color.blue, Color.red); GraphicsStub g = new GraphicsStub(); GraphicsStub gblue = new GraphicsStub(); gblue.setColor(Color.blue); GraphicsStub gline1 = new GraphicsStub(); gline1.drawLine(22, 341, 104, 106); GraphicsStub gline2 = new GraphicsStub(); gline2.drawLine(104, 106, 22, 341); ls.plot(g); assertTrue (g.toString().contains(gblue.toString())); assertTrue (g.toString().contains(gline1.toString()) || g.toString().contains(gline2.toString())); } ⋮

The (main) mock graphics object is created here.

The function being tested in called here.

Then, assertions like this one can test the info recrded in the mock object.

Mock Frameworks

Increasingly, unit test frameworks are including special support for mock object creation.

2.1 Google Mock (C++)

Page 293: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

For example, the Google Mock Framework provides support for creating mock objects that automatically keep a log of calls made to them.

And adds special functions and test assertions to both test that the expected calls were made and controlling what results will be returned from those calls.

**Mocking Up an Example **

Suppose that we are writing an application that uses this class:

class Turtle { ⋮ virtual ~Turtle() {} virtual void PenUp() = 0; virtual void PenDown() = 0; virtual void Forward(int distance) = 0; virtual void Turn(int degrees) = 0; virtual void GoTo(int x, int y) = 0; virtual int GetX() const = 0; virtual int GetY() const = 0; };

To set up the test of the application code that uses this, we derive a mock class that has the same interface…

A Mock Class

#include "gmock/gmock.h" class MockTurtle : public Turtle { public: ... MOCK_METHOD0(PenUp, void()); MOCK_METHOD0(PenDown, void()); MOCK_METHOD1(Forward, void(int distance)); MOCK_METHOD1(Turn, void(int degrees)); MOCK_METHOD2(GoTo, void(int x, int y)); MOCK_CONST_METHOD0(GetX, int()); MOCK_CONST_METHOD0(GetY, int()); };

Note that both the macro names and the function signatures are related to the original interface.There are scripts that can sometimes generate this automatically.

Using the Mock

Page 294: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Then in unit tests for the application class, we

1. use instances of the mock class2. Write assertions that describe how we expect the stub to be exercised.

#include "mock-turtle.h"#include "gmock/gmock.h"#include "gtest/gtest.h"using ::testing::AtLeast; TEST(DrawACircle, CanDrawSomething) { MockTurtle turtle; EXPECT_CALL(turtle, PenDown()) .Times(AtLeast(1)); Painter painter(&turtle); EXPECT_TRUE(painter.DrawCircle(0, 0, 10)); }

So, if we call painter.drawCircle(...), we

expect it to return trueexpect it to call tutle.PenDown() at least once.

Stubs can Generate Output

EXPECT_CALL(g, foo(_)) .TIMES(3) .WillRepeatedly(Return(150)); EXPECT_CALL(g, foo(1)) .WillOnce(Return(100)); EXPECT_CALL(g, foo(2)) .WillOnce(Return(200));

This assertion says

a function g.foo(x) will be called 5 times,with x being 1 and 2, one time eachand an unspecified value on the other three calls

It also specifies what value should be returned on each call.

If the function is called 6 times, or if one or more of the 5 expected calls are not made before the test case ends, the EXPECT_CALL assertion fails, just likeother test assertions.

Page 295: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.2 JMockit (Java)There are a number of popular mocking frameworks for Java: JMock, EasyMock, Mockito

JMockit is one of newer ones.

IMO, it seems one of the more elegant.

2.2.1 The Record-Replay-Verify Model

A test with JMockit mock objects typically follows a structure of

RecordWe establish our expectations of what calls will be made on our mock objects by separately executing those calls in a recording mode.

In this phase we also record any return/output values we want our mocks to return from those calls.

ReplayWe actually perform the test, calling upon some functions of the ADT under test that, in the run, we expect will make those calls on the mocks. The actualcalls made are compared against the “recording” we made earlier.

We fail the test if we do not see the expected (recorded) calls.

VerifyMore detailed checks are made to see if the test matched criteria other than simply having called the expected functions in the expected order.

We may check the parameters supplied to those calls and/or check to see that other mock functions were not called.

3 Case Studies3.1 Example 1 (Spreadsheet CLI)In our spreadsheet example, we had these stories in the first increment:

As a calculation author I would like to load a spreadsheet via the CLI.As a calculation author I would like to generate a value report via the CLI.

Page 296: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

I decided to merge these as, together, they represented the minimum testable behavior on the CLI.

However, during this first project increment, the spreadsheet itself has not been implemented.

I had, for an earlier story, taken a first pass at designing the spreadsheet API:

package edu.odu.cs.espreadsheet; ⋮ public class Spreadsheet implements Iterable<CellName> { public Spreadsheet() { // TODO } ⋮ /** * Loads a spreadsheet from a file or other input source. Input format is * one assignment per line. * * @param input an input source * @throws IOException if assignments cannot be parsed form the input. */ public void load (Reader input) throws IOException { // TODO Auto-generated method stub } ⋮ /** * Write out the value report for the spreadsheet, giving the current value of * each non-empty cell. * * @param output output device */ public void report (Writer output) { // TODO Auto-generated method stub } }

Page 297: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The CLI

I expected the CLI to look something like:

package edu.odu.cs.espreadsheet.cli; ⋮ import edu.odu.cs.espreadsheet.Spreadsheet; public class Run { ⋮ public Run(String filename) { // TODO } /** * Load the indicated spreadsheet and generate its value report. * @throws IOException if the spreadsheet cannot be loaded */ public void doIt() throws IOException { ⋮ } public static void main (String[] args) throws FileNotFoundException, IOException { if (args.length != 1) { System.err.println("Usage: must supply a path to a spreadsheet file as a command line parameter."); System.exit(-1); } new Run(args[0]).doIt(); } }

because this is a pretty standard pattern for me.

Testing With a Spreadsheet

Now, if I had been working bottom-up, then by the time I looked at the CLI, I would have a working spreadsheet and could write some “real” tests of the CLI:

ITestCLI.java +

Page 298: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

package edu.odu.cs.espreadsheet.cli; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import org.junit.BeforeClass; import org.junit.Test; public final class ITestCLI { static Path testDataDir = Paths.get("target/itest-data"); @BeforeClass public static void setupDir() { File dir = testDataDir.toFile(); dir.mkdir(); } @Test public void testRunNonExistentFile() throws FileNotFoundException, IOException { Run running = new Run("target/testdata/nonExistent.ss"); boolean thrown = false; try { running.doIt(); } catch (FileNotFoundException ex) { thrown = true; } assertTrue (thrown); } @Test public void testBadFile() throws FileNotFoundException, IOException { Path badDataPath = testDataDir.resolve("badData.ss"); Files.write(badDataPath, Arrays.asList("a12", "ab2=1"), Charset.forName("US-ASCII"));

Page 299: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Run running = new Run(badDataPath.toString()); boolean thrown = false; try { running.doIt(); } catch (IOException ex) { thrown = true; } assertTrue (thrown); } @Test public void testSimpleAssignments() throws FileNotFoundException, IOException { Path simpleDataPath = testDataDir.resolve("simpleData.ss"); Files.write(simpleDataPath, Arrays.asList("a12=12", "ab2=1"), Charset.forName("US-ASCII")); // Capture System.out ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream stringStream = new PrintStream(baos); PrintStream savedOut = System.out; System.setOut (stringStream); try { Run running = new Run(simpleDataPath.toString()); running.doIt(); } finally { //Restore System.out System.out.flush(); System.setOut(savedOut); } String reportOutput = baos.toString(); assertTrue (reportOutput.startsWith("a12=12")); assertTrue (reportOutput.contains("ab2=1")); } @Test public void testEvaluationPerformed() throws FileNotFoundException, IOException { Path simpleDataPath = testDataDir.resolve("evalData.ss"); Files.write(simpleDataPath, Arrays.asList("a12=10*ab2", "ab2=2"), Charset.forName("US-ASCII")); // Capture System.out ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream stringStream = new PrintStream(baos);

Page 300: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

PrintStream savedOut = System.out; System.setOut (stringStream); try { Run running = new Run(simpleDataPath.toString()); running.doIt(); } finally { //Restore System.out System.out.flush(); System.setOut(savedOut); } String reportOutput = baos.toString(); assertTrue (reportOutput.startsWith("a12=20")); assertTrue (reportOutput.contains("ab2=2")); } }

This has tests for the cases:

Input file does not existInput file exists but has parsing errorsInput file OK, contains simple numeric assignmentsInput file OK, actually requires some expression evaluation and references to other cells.

I’m not attempting here to thoroughly test all value kinds and expression operators.That would take place i nthe tests of those other classes (Value, Expression, etc.)

Problems with that Test

I won’t be able to pass it until we are near the end of the overall implementation.It could be passed by other means (e.g., if the CLI used the Spreadsheet save operation instead of report, but save was buggy and listed values insteadof expressions).It is heavily dependent on exact I/O formatting and other details that might change when we consider the relevant classes in more detail.

i.e., it is dependent on the Spreadsheet and other classes.

This is actually an integration or system test, not a unit test.

Unit Testing Without a Spreadsheet

For a unit test of the CLI, I can mock the spreadsheet:

TestCLI.java +

Page 301: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

package edu.odu.cs.espreadsheet.cli; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Reader; import java.io.Writer; import mockit.Expectations; import mockit.Mocked; import org.junit.Test; import edu.odu.cs.espreadsheet.Spreadsheet; public final class TestCLI { @Mocked Spreadsheet ss; ➀ @Test public void testRun() throws FileNotFoundException, IOException { // Record phase: expectations on mocks are recorded; empty if there is nothing to record. new Expectations() {{ ➁ ss.load(withAny((Reader)null)); ➂ ss.report(withAny((Writer)null)); ➃ }}; // Replay phase: invocations on mocks are "replayed"; here the code under test is exercised. Run running = new Run("ivy.xml"); ➄ running.doIt(); // Verify phase: expectations on mocks are verified; empty if there is nothing to verify. ➅ } }

➀ Here I announce that I am mocking the spreadsheet class.

JMockit does not mock just this variable – it mocks all Spreadsheet objects in this test.A different approach than used in other mocking frameworks.

➁ The Expectations block starts the recording.

There are different varieties of Expectations. This one indicates that we expect to see the replayed function calls in the order we list them here.Other varieties allow the calls to occur in arbitrary order.

Page 302: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

➂ First we expect to see a load call made on the spreadsheet. Because Java Reader classes can’t be compared for equality, the test says that any Readervalue is acceptable.

➃ Later we expect to see a report call made on the spreadsheet.

➄ Now we do the actual test.

➅ We don’t need any additional verification at the end.

Are We OK With This?

You might argue that this test is

Simple

Not necessarily a bad thing. It serves as a pretty clear specification of what we expect the CLI to do.

Not very thorough

It does not check to be sure that there aren’t defects in the SpreadsheetBut that’s the job of the future Spreadsheet unit tests, not of the CLI unit test.It does not check for unexpected bad interactions between the CLI and the Spreadsheet.

But interactions between classes are the province of integration tests, not unit tests.And we don’t throw out that first test. It’s an integration test for use later when the Spreadsheet is actually implemented.

3.2 Example 2: Adding Numeric Literals to the SpreadsheetShortly after the prior example, I had the story:

As an API user I would like to add a numeric literal to a cell in a spreadsheet.

The task list I came up with for this was:

1. Check Spreadsheet API2. Design Cell API3. Design Expression API4. Add Unit test to Spreadsheet5. Add Integration test to Spreadsheet6. Add Unit test to Expression

Page 303: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

7. Add Unit test to Cell8. Implement Expression parse for numeric literals9. Implement Cell storage of expressions

10. Implement Spreadsheet expression load11. Check in changes.

That may look like a lot, but it boils down to a common pattern:

1. Make changes to the API to support the new functionality2. Write Unit tests for the new functionality3. If any of those tests used stubs or mocks, write integration or system tests for the behavior.4. Implement the new functionality5. Wrap things up

We expect that, at the end of step 4, we will pass all the new units tests devised in step 2.

We may not be able to pass the new integration & system tests until other parts of the system have been finished.

3.2.1 Adding to the APIs

I made a conscious decision not to expose the internal Expression class as part of the API:

old

package edu.odu.cs.espreadsheet; ⋮ public class Spreadsheet implements Iterable<CellName> { ⋮ /** * Get the formula stored in the indicated cell. * * @param cell a cell in the spreadsheet * @return the formula in that cell, or null if no formula has been placed there */ public Expression getFormula (CellName cell) { ⋮ } /** * Assigns a formula to the indicated cell. * * @param cell a cell in the spreadsheet

Page 304: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

* @param newFormula an expression for future evaluation (may be null) * @throws ExpressionParseError if assignments cannot be parsed from the input. */ public void assignFormula (CellName cell, Expression newFormula) throws ExpressionParseError { ⋮ } ⋮ }

new

package edu.odu.cs.espreadsheet; ⋮ public class Spreadsheet implements Iterable<CellName> { ⋮ /** * Get the formula stored in the indicated cell. * * @param cell a cell in the spreadsheet * @return the formula in that cell, or null if no formula has been placed there */ public String getFormula (CellName cell) { ⋮ } /** * Assigns a formula to the indicated cell. * * @param cell a cell in the spreadsheet * @param newFormula an expression for future evaluation (may be null) * @throws ExpressionParseError if assignments cannot be parsed from the input. */ public void assignFormula (CellName cell, String newFormula) throws ExpressionParseError { ⋮ } ⋮ }

A welcome side effect of this change is to make independent testing of these classes even easier.

Page 305: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Cells contain Expressions

Cell.java +

package edu.odu.cs.espreadsheet; import edu.odu.cs.espreadsheet.expressions.Expression; import edu.odu.cs.espreadsheet.values.Value; /** * A single cell withing a spreadsheet. * * @author zeil * */publicclass Cell { private Spreadsheet ssheet; private CellName name; private Expression formula; private Value value; /** * Create a new cell * @param sheet the spreadsheet containing this cell * @param name the name of this cell */ public Cell (Spreadsheet ssheet, CellName name) { this.ssheet = ssheet; this.name = name; this.formula = null; this.value = null; } public CellName getName() { return name; } /** * Get the formula associated with this cell. * * @return an expression or null if the cell is empty

Page 306: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

*/ public Expression getFormula() { return formula; } public void putFormula(Expression e) { formula = e; value = null; } public Value getValue() { if (value == null && formula != null) value = formula.evaluate(ssheet); return value; } public String toString() { return name.toString() + "::" + formula + "::" + value; } public int hashCode() { return name.hashCode(); } public boolean equals(Object obj) { if (obj instanceof Cell) { Cell other = (Cell)obj; return name.equals(other.name); } else return false; } }

Expressions can be Evaluated

Expression.java +

Page 307: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

package edu.odu.cs.espreadsheet.expressions; import java.io.StringReader; import edu.odu.cs.espreadsheet.ExpressionParseError; import edu.odu.cs.espreadsheet.Spreadsheet; import edu.odu.cs.espreadsheet.values.Value; /** * Expressions can be thought of as trees. Each non-leaf node of the tree * contains an operator, and the children of that node are the subexpressions * (operands) that the operator operates upon. Constants, cell references, * and the like form the leaves of the tree. * * For example, the expression (a2 + 2) * c26 is equivalent to the tree: * * * * / \ * + c26 * / \ * a2 2 * * @author zeil * */public abstract class Expression implements Cloneable { /** * How many operands does this expression node have? * * @return # of operands required by this operator */ public abstract int arity(); /** * Get the k_th operand * @param k operand number * @return k_th operand if 0 < k < arity() * @throws IndexOutOfBoundsException if k is outside of those bounds */ public abstract Expression operand(int k) throws IndexOutOfBoundsException; /** * Evaluate this expression, using the provided spreadsheet to resolve * any cell referneces. * * @param usingSheet spreadsheet form which to obtain values of

Page 308: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

* cells referenced by this expression * * @return value of the expression or null if the cell is empty */ public abstract Value evaluate(Spreadsheet usingSheet); /** * Copy this expression (deep copy), altering any cell references * by the indicated offsets except where the row or column is "fixed" * by a preceding $. E.g., if e is 2*D4+C$2/$A$1, then * e.copy(1,2) is 2*E6+D$2/$A$1, e.copy(-1,4) is 2*C8+B$2/$A$1 * * @param colOffset number of columns to offset this copy * @param rowOffset number of rows to offset this copy * @return a copy of this expression, suitable for placing into * a cell (ColOffSet,rowOffset) away from its current position. * */ public abstract Expression clone (int colOffset, int rowOffset); /** * Copy this expression. */ @Override public Expression clone () { return clone(0,0); } /** * Attempt to convert the given string into an expression. * @param in * @return */ public static Expression parse (String in) throws ExpressionParseError { try { parser p = new parser(new ExpressionScanner(new StringReader(in))); Expression expr = (Expression)p.parse().value; return expr; } catch (Exception ex) { throw new ExpressionParseError("Cannnot parse " + in); } }

Page 309: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

@Override public String toString () { ⋮ } @Override public abstract boolean equals (Object obj); @Override public abstract int hashCode (); // The following control how the expression gets printed by // the default implementation of toString /** * If true, print in inline form. * If false, print as functionName(comma-separated-list). * * @return indication of whether to print in inline form. * */ public abstract boolean isInline(); /** * Parentheses are placed around an expression whenever its precedence * is lower than the precedence of an operator (expression) applied to it. * E.g., * has higher precedence than +, so we print 3*(a1+1) but not * (3*a1)+1 * * @return precedence of this operator */ public abstract int precedence(); /** * Returns the name of the operator for printing purposes. * For constants/literals, this is the string version of the constant value. * * @return the name of the operator for printing purposes. */ public abstract String getOperator(); }

Page 310: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A lot of this design was lifted from an earlier project of mine.

Expression is an abstract class – we never expect to see any actual objects of this type.

But we will have lots of interesting subclasses (one per operator) that will have “real” instances.

Numeric Literals

This story requires just enough expression handling to deal with numeric literals. So we’ll need an API for numeric literals. We’ve already covered that,however.

3.2.2 Writing the Unit tests

NumericLiteral

NumericLiteral needs a good set of unit test cases. We’ve looked at those tests earlier.

The NumericLiteral test is a good example of unit testing, but did not use stubs or mocks.

It is, in effect, a bottom-level class whose implementation does not require that we write any additional classes.

Cells

Although I had a task to create a unit test for Cell, currently it really only has encapsulated data member get/set functions, so I gave that a pass.

Spreadsheet

An existing unit test for spreadsheets was augmented to cover this story of inserting numeric literals.

MockTestSpreadSheet.java +

/** * */package edu.odu.cs.espreadsheet; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import mockit.Expectations;

Page 311: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

import mockit.Mocked; import org.junit.Test; import edu.odu.cs.espreadsheet.expressions.Expression; import edu.odu.cs.espreadsheet.expressions.NumericLiteral; /** * @author zeil * */public class MockTestSpreadSheet { @Mocked Expression expr; @Test public final void testConstructor() { Spreadsheet s = new Spreadsheet(); assertEquals (0, s.getDimension()); assertNull (s.getFormula(new CellName("a1"))); assertFalse (s.iterator().hasNext()); } @Test public final void testNumericLiteralInsertion() throws ExpressionParseError { final Spreadsheet s = new Spreadsheet(); final String input = "1.234"; new Expectations() {{ Expression.parse(input); result = new NumericLiteral(input); expr.toString(); result = "1.234"; }}; CellName cn = new CellName("a1"); assertNull (s.getFormula(cn)); assertNull (s.getValue(cn)); s.assignFormula(cn, input); assertEquals (input, s.getFormula(cn)); } @Test(expected = ExpressionParseError.class) public final void testParsingError() throws ExpressionParseError { final Spreadsheet s = new Spreadsheet(); final String input = "1.23.4"; new Expectations() {{ Expression.parse(input); result = new ExpressionParseError(); }};

Page 312: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

CellName cn = new CellName("b2"); assertNull (s.getFormula(cn)); assertNull (s.getValue(cn)); s.assignFormula(cn, input); assertTrue(false); } }

Two new test cases added to an existing test for spreadsheets

Inserting any formula/expression is done by passing a string to the spreadsheet, which must parse that string to yield the actual expression.

Parsing would not be implemented yet in this story.Calls for a Mock!

New Expression test case 1

Let’s break this testcase down:

public final void testNumericLiteralInsertion() throws ExpressionParseError { final Spreadsheet s = new Spreadsheet(); final String input = "1.234"; new Expectations() {{ ➀ Expression.parse(input); result = new NumericLiteral(input); expr.toString(); result = "1.234"; }}; CellName cn = new CellName("a1"); assertNull (s.getFormula(cn)); assertNull (s.getValue(cn)); s.assignFormula(cn, input); ➁ assertEquals (input, s.getFormula(cn)); ➂ }

➀ The Expectations block is our recording phase.

We expect that, once we try to assign a formula (a string) to a cell (➁ ) that the Expression.parse function will be called to convert the string into anexpression.

Page 313: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

That parse function isn’t going to be implemented yet. But we expect that the result of parsing the input string for this test should simply be aNumericLiteral.

The result = establishes what return value should be supplied when we “play back” this recording.

Back to ➀ , again – we expect that when we call getFormula (➂ ), this process will need ot be reversed and the Expression toString() function will becalled to convert an expression back into string form.

New Expression test case 2

The other new test case starts with a similar structure:

@Test(expected = ExpressionParseError.class)public final void testParsingError() throws ExpressionParseError { final Spreadsheet s = new Spreadsheet(); final String input = "1.23.4"; new Expectations() {{ Expression.parse(input); result = new ExpressionParseError(); }}; CellName cn = new CellName("b2"); assertNull (s.getFormula(cn)); assertNull (s.getValue(cn)); s.assignFormula(cn, input); assertTrue(false); }

But in this case we are supplying an invalid input:

Here we tell JMockIt that we expect the spreadhseet to invoke the parse operation, but that we want the simulated parser to throw an exception.

Here we are telling JUnit that the expected outcome of this test case is that an exception will be thrown (and not caught).

3.2.3 Integration Tests

Because one of our new unit tests used mocks, we should add an integration to system test now that we will fail now but will pass some time in the future whenthe missing modules have been implemented:

ITestSpreadSheet.java +

package edu.odu.cs.espreadsheet; import static org.junit.Assert.assertEquals;

Page 314: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.StringReader; import org.junit.Test; import edu.odu.cs.espreadsheet.values.NumericValue; import edu.odu.cs.espreadsheet.values.Value; /** * @author zeil * */public class ITestSpreadSheet { @Test public final void testConstructor() { Spreadsheet s = new Spreadsheet(); assertEquals (0, s.getDimension()); assertNull (s.getFormula(new CellName("a1"))); assertFalse (s.iterator().hasNext()); } @Test public final void testNumericLiteralInsertion() throws ExpressionParseError { final Spreadsheet s = new Spreadsheet(); CellName cn = new CellName("a1"); assertNull (s.getFormula(cn)); assertNull (s.getValue(cn)); s.assignFormula(cn, "1.234"); assertEquals ("1.234", s.getFormula(cn)); Value v = s.getValue(cn); assertNotNull(v); assertTrue (v instanceof NumericValue); NumericValue nv = (NumericValue)v; assertEquals (1.234, nv.getDouble(), 0.0001); } @Test public final void testParsingError() {

Page 315: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

final Spreadsheet s = new Spreadsheet(); CellName cn = new CellName("b2"); assertNull (s.getFormula(cn)); assertNull (s.getValue(cn)); boolean thrown = false; try { s.assignFormula(cn, "1.23.4"); } catch (ExpressionParseError e) { thrown = true; } assertTrue (thrown); assertNull (s.getFormula(cn)); Value v = s.getValue(cn); assertNull(v); } }

Basically, all we did here was to strip out the mocking portions of the unit tests!

4 Are Mock Frameworks Useful?My experience with them is still somewhat limited.

When they work, they seem wonderful.

many professionals swear by them

Some mock frameworks impose strong limits on the design of the classes that can be mocked

Mock proponents argue that this is a virtue, enforcing what they see as preferred design styles.

I’m not convinced.

One reason I prefer JMockit to other Java mock frameworks is that it imposes far fewer limitations on the design of the classes to be mocked.

Most of the published examples and tutorials focus on primitive types for function parameters and return values.

My experience suggests that functions taking ADTs as parameter values or returning ADTs can be handled. It’s a little more complicated, but notterribly so.

Page 316: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Version ControlSteven J Zeil

Last modified: Sep 14, 2017

Contents:1 Issues in Version Control2 Background - Changing the Code Base

2.1 Integrating Changes3 Approaches and Tools

Abstract

Version control (a.k.a. version management is concerned with the management of change in the software artifacts being developed.

In this lesson we look at the kind of practical problems that arise during software development and that can be addressed by proper version control.

maintaining the history of changes to the code baseexploring possible changes without breaking the code baseallowing collaboration among developers needing simultaneous access to the code base

Version control is sometimes considered a sub-area of configuration managementa.k.a., Software Configuration Management (SCM)Oddly enough, many tools labeled and marketed as SCM tools only address version control

1 Issues in Version ControlThe issues addressed by version control are:

History

How has the software changed since date-or-version-number? Who made those changes? Why were they made? Can we go back?

Exploration

Page 317: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Can we try out a set of plausible changes without affecting the “main” software build? Even if exploration of the effects of those changes may takea long time?

Collaboration

Can we have multiple developers working on the code without interfering with one another’s work?

2 Background - Changing the Code Base

ed

One of the earliest Unix text editors, ed applies a series of editing commands like ‘a’ to append to th end of a file, ‘i’ to insert a line at the current location, ‘d’to delete the current line, etc.

Few people use ed nowthough its line-oriented “child”, sed is still a popular scripting tool.

diff

diff compares two files line by line, listing the differences between them.

Differences are listed as a series of line replacements, insertions, and/or deletions

Reduces each line to a hash codeUses the dynamic programming algorithm for computing the Levenshtein distance between the two sequences of hash codes to obtain anapproximately shortest sequence of commands

Can emit differences as ed commands:

diff --ed file1 file2 > file12.diff echo w file2 >> file12.diff ## many days later...# ed file1 < file12.diff

would “rebuild” file2 from file1 and the diff.

patch

Page 318: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

patch takes a slightly more sophisticated approach to the idea of applying a diff output to a file

diff file1 file2 > file12.diff ⋮ patch file1 file12.diff

Allows a variety of different diff variants

Can detect if file1 has already been changed so that the line numbers and other info in the patch file file12.diff are no longer accurate.

Attempts to compensate

2.1 Integrating ChangesSuppose that we have two patch files created from the same base file file1

patch -o file2a file1 patchA patch -o file2b file1 patchB

Change integration is the problem of combining both sets of changes to form a desired file file2.

Two-way Change Integration

patch -o file2a file1 patchA patch -o file2b file1 patchB

How do we know which patched file is “correct”, or whether we need some combination of the changes?

Two-way procedure:

1. Compare file2a and file2b2. Wherever the two are different, prompt the human to select the desired change.

Three-way Change Integration

Takes the base file into account as well as the two changed files.

Page 319: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

patch -o file2a file1 patchA patch -o file2b file1 patchB

Three-way procedure:

1. Compare file1 and file2a, then file1 and file2b2. Any lines that differ from file1 in only one of the two other files can be applied automatically.3. Wherever both file2a and file2b are different from file1, prompt the human to select the desired change.

This is called a conflict.

3 Approaches and Tools

Version Control Systems

If we could extend patch multiple files at once, we could, in theory, patch an entire software system to move it from version 1 to version 2, then patch it againto move to version 3, etc.

This would be the heart of a version control system,

Approaches and Tools

Local version control systems manage history by setting aside directories on the same file system where the software under control is housed.

sccs, rcs

Centralized version control systems keep the system history at a centralized location accessible via the network.

Developers check out a copy of the current (or a desired older) version of the software onto their own machines.

CVS, Subversion

Distributed version control systems allow developers to keep the full system history on their own machines.

A central location may hold a base copy for management/distribution purposes, but this is not required.

git

Page 320: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Local Version Control (sccs, rcs)Steven J Zeil

Last modified: Dec 21, 2019

Contents:1 History2 Exploration3 Collaboration4 Strengths and Weaknesses

Abstract

Local version control stores the history of the code base on the same disk storage used for the code under development.

In this lesson we will look at how this approach supports the problems areas of

history maintenance,exploration of alternatives, andcollaboration among developers

Particular attention will be paid to the locking mechanism used to support safe simultaneous access.

The earliest version control systems in wide use were sccs and the open source rcs.

We’ll focus on rcs

The “repository” of historical information is kept as a “special” subdirectory, named RCS

Sharing of repositories is possible only via the operating system’s underlying mechanism for sharing access to directories

permissions, linking

Basic rcs Operations

ci Check In a file from the working directory into the repository

co Check Out a file from the repository into the working directory

Page 321: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

rcsdiff Compare two versions of a file.

rcsmerge

1 Historymkdir RCS

Creates an RCS repository for the files in the current directory (only)

The repository is currently empty

ci filename

Checks files in to the repository

If the file is not in there yet, it is addedIf it is in there, then this becomes the new/current revisionEach check in is assigned a new, ascending revision number

Somewhat surprisingly, deletes the file from the current directory

co -l filename

Checks out the most recent version of that file from the repository, storing it in the working directory.

Adding a -r v option allows check out of a specific revision number

Revision Numbers

Clearly there was an intent that revision numbers also serve as version numbers.

Page 322: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A special option allows you to force a change to the leading digit,

e.g., to move from version 1.12 to 2.0

Problem is that each file’s revision number changes independently

So your intended release “version 2.1” might use revision 2.1 if adt.h, revision 2.5 of adt.cpp, revision 2.3 of main.cpp, etc.

Versions can be checked out by date instead:

“check out whatever version was current as of 12/13/2012”

Repeated over all files, would give a coherent view of the project status as of that date

Naming Revisions

Revisions can be named:

ci -N "v1.2" -t "Public release 1.2" *.h *.cpp

and later checked out by name instead of by exact revision number

Note also the option to add explanatory text at the time of the checkout

Later version managers would make this “mandatory”

Implementation

rcs is essentially a systematic way of creating and organizing patches.

The repository always contains the current version of the file plus enough diffs/patches to move back to any prior revision.

The current version is always available immediately.

Diffs are used to go back in time

Page 323: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Originally considered an important point in supporting efficient access to the most commonly needed file.

Now, probably not so important

2 Exploration

Exploring Alternatives

Suppose that we have worked through a few revisions and then get an idea that might not pay off.

We can start a branch to explore our idea while others continue work on the main trunk.

ci -r1.3.1 _filename_

Checks in our current version of filename as a new branch of development, numbered 1.3.1.1

1.3.1.1 is the trunk version from which we branched out

1.3.1.1 is the branch number

1.3.1.1 is the revision number within the branch

Working in a Branch

Subsequent check-ins of both the main trunk (1.3) and of our branch version will maintain separate revision numbers:

Note that checking out the most recent version along a branch is not as efficient as checking out the most recent version on the trunk.

Page 324: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Merging a Branch

If the idea in the branch does not pay off, the branch can simply be abandoned.

If you decide to adopt the changes in the branch, you can elect to merge it back into the trunk.

The rcsmerge command is used to conduct the merge,Need to resolve any conflicts introduced by continued development along the trunk.

then the resulting combined file checked in with a trunk number

Multiple Merges

After a merge

Page 325: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

We might opt to discontinue using the branch

Or we might continue working along it, eventually generating more changes to be merged into the system

Combating Drift

Over time, a long-running branch can get so far out of sync with changes being made to the trunk that the final merge becomes difficult or even impossible.

An effective strategy for combating this is to periodically merge the trunk into the branchthe reverse of the “normal” merge direction

3 Collaborationrcs supports collaboration by locking files

Most checkouts like this

co filename

obtain a read-only copy of the file.

*nix permissions 400Can be used to compile system, but cannot be changed

(Of course, you can always chmod, but that’s cheating.

Page 326: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Locks

A checkout like this

co -l filename

requests a locked version of the file.

Request fails if a locked version already exists somewhere.If successful, programmer receives a copy with write permission.Lock persists until the programmer checks in changes or explicitly releases the lock (which deletes the file from their directory, forcing them tocheck out an unlocked, read-only version again).

4 Strengths and Weaknessesrcs addresses history, exploration, & collaboration concerns

but has weaknesses in each area

History

rcs tracks files in a directory.

Each file is tracked separately.

No support for deletion of file

Unless you know not to request a file, you will always get the last version before it was deleted.

No support for creation of new files

If you request revisions associated with very old dates, you will get version 1.1 even if the file did not actually exist as of that date.

No support for renaming files

Appears to be a deletion and a subsequent creation of a new, unrelated file

Each directory is tracked separately

Poor support for multi-directory projects

Page 327: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Exploration Issues

Branching and merging is often confusing.

Collaboration Issues

Locks are frequently abused

e.g., people forget to release a lock, forcing team members to waitPeople grab locks they don’t really need.

Cheating on locks is easy

People get in the habit of cheating to cope with lock abuseAnd eventually start cheating with less and less provocation.

Page 328: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Centralized Version Control (CVS, Subversion)Steven J Zeil

Last modified: Dec 21, 2019

Contents:1 CVS

1.1 History1.2 Exploration1.3 Collaboration

2 Subversion2.1 History2.2 Exploration2.3 Collaboration2.4 Eclipse Integration

Abstract

Centralized version control stores the history of the code base on a separate server from which copied can be provided to all developers.

In this lesson we will look at the advantages of centralized version control over local control. Particular attention will be paid to the area of collaboration wherelocal locking mechanisms are replaced by after-fact detection and resolution of conflicting changes.

We will look at one of the most influential version control systems, CVS.

Centralized Version Control

rcs kept its repository of history information in the “live” working directories.

Each directory of a project had a separate repository.

Sharing among team members relied on the rather limited Unix protection scheme.

Centralized version control systems keep a project repository in a location separate from the programmer’s work area.

Allows one repository to track a project’s entire directory tree

Encourages/requires use of a network-based sharing scheme

Page 329: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Allowing therefore a more distributed work effort

1 CVSBased on rcs

Many of the concepts and commands are similar

Uses a centralized store

can be on local or remote machine

1.1 HistoryCheck-in and check-out are similar to rcs

No locks, however

By default, scope of commands is an entire directory tree

cvs checkout projectRootDir

makes a copy of projectRootDir in the working directory, checking out the most recent version of everything in the project.

Similarly,

cd projectRootDir cvs commit -m "Added unit tests"

checks in any changes from the working directory on down.

Unix nerd alert: I often think of the cvs doSomething commands as if they were

find . -type f -exec rcsDoSomething {} \;

Where’s the Repository?

Page 330: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The earlier commands presume that we have, somehow, already established a connection with the repository.

In practice this is either done via earlier steps or added as additional options to individual commands

Local CVS Repositories

If the repository is on a local file file system,

you can specify it via -d:

cvs -d /usr/local/cvsroot checkout myProject/projectRootDir

or record this info in an environment variable:

setenv CVSROOT /usr/local/cvsroot cvs checkout myProject/projectRootDir

Remote Repositories

The same techniques (-d, CVSROOT) can be used to specify remote repositories.

Instead of simply specifying the path to the repository, give

[:method:][[user][:password]@]hostname[:[port]]/path/to/repository

Specifying the password in this way is a really bad idea

Usually, use

cvs login

to open a session (rather than get prompted for a password on every command).

Connection method: pserver

The pserver method is a built-in network connection method with password control.

Page 331: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Port 2401

Falling out of favor

pserver Exmaple

sirius:~/temp/tmp> setenv CVSROOT :pserver:[email protected]:/home/cvs/dlibsirius:~/temp/tmp> cvs loginLogging in to :pserver:[email protected]:2401/home/cvs/dlib CVS password: *****sirius:~/temp/tmp> cvs checkout AlgAE cvs checkout: Updating AlgAEU AlgAE/.project U AlgAE/AlgAE_layout.odg U AlgAE/LICENSE.txt U AlgAE/README.txt U AlgAE/build.xml U AlgAE/buttons.gif U AlgAE/buttons.odg U AlgAE/jhbasic.jar U AlgAE/junit-4.10.jar cvs checkout: Updating AlgAE/AlgAE_screenshot.png ⋮ sirius:~/temp/tmp> ls -ld AlgAE drwxrwxr-x 11 zeil faculty 1024 Feb 21 13:39 AlgAE/

ssh Connections

If you have ssh access to the machine running the CVS server, you can do

sirius:~/temp/tmp> setenv CVSROOT :extssh:[email protected]:/home/cvs/dlibsirius:~/temp/tmp> cvs checkout AlgAEThe authenticity of host 'cvs.cs.odu.edu (128.82.4.233)' can't be established. RSA key fingerprint ⋮ Password:

The History Commands

checkout: gets an initial copy of what’s on the server

Page 332: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

update: checks to see if something newer than a local file copy is on the server, and if so, replaces the local copy by the remote one

commit: sends any local files that are newer than the server copy to the server as new revisions

add: places files that are not currently being tracked by CVS under version control

does not affect the server until committed

import: places a directory tree under version control

release: detaches the directory from the CVS server (if no files need to be committed)

1.1.1 Eclipse Integration

Eclipse includes CVS support in its normal distributions.

From Window->Open Perspective->Other..., select CVS Repository Exploring

Of course, you will need to have access to a repository before you see anything.

Checking Out an Existing Project

Pulling an existing project from CVS into Eclipse is pretty straightforward:

From the New Project menu, select “Project from CVS”Fill in the repository informationSelect the “module” (project)if given an option, request the use of the wizard to configure the checked-out projectSelect the “Head”, a branch, a version, or by date

Eclipse Integration: Creating a Project

To add a new project to an existing repository:

Set up the project as normal on your local machine

“Clean” the project of any object code, compiled classes, archives, etc. that are products of the project build are not present.This is optional, but saves work later.

Right-click on the project and select Team->Share Project...

Page 333: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Fill in the repository information

You will eventually be shown a list of files to be committed.

Review them carefully. If you check in something that you don’t want under version control, it’s virtually impossible to remove later.Think carefully about adding the Eclipse .project, .classpath, etc. files to the control set.

Working with History in Eclipse

Right-click on a file or directory and look in the “team” menu

Add to version control

Commit…

Update

Synchronize with repository

Combines commit and update, lets you select which files go in which directionBe careful of adding build products to the repository as you commit.

Exercise the options to “remove from view” or, for a more permanent solution, “Add to .cvsignore”

You might want to put .cvsignore under version control.

Tag (name)

Show History

Examining History in Eclipse

Right-click on a file or directory and look for

Compare (local copy) withhead, specific branches

1.2 ExplorationBranches

Page 334: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Same as rcs

Creating Branches

Make sure that you have checked in all the latest changes in your current working project.

Right-click on the project root directory and select Team <span>&#x21D2;</span> Branch\dots.

Enter a name for your branch.

Leave “Start working in the branch” checked. Click OK.

All the files under that root directory will be marked as belonging to a new branch.

As you work on this branch, you can make frequent use of the Compare With ... Head option to check for changes in the main trunk that you mightwant to incorporate into your branch code.

Merging a Branch Back Into the Main Trunk

1. Make sure that your copy of the branch is up-to-date, all changes checked in.If you want to allow for continued use of the branch after the merge, add a tag on the branch.

Right-click on a project with an up-to-date copy of the branch, and select “Team ⇒ Tag as Version … ”

1: To begin the actual merge, start with an up-to-date copy of the main trunk (HEAD).

You may already have one,Or you can right-click on the branc project, select “Team ⇒ Replace with ⇒ Branch or Version” and select HEAD.

This will actually check out a copy of the HEAD, replacing code in the branch.

Page 335: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

That should not be a problem, since you made sure that you had checked in all changes in the 1st step. But it is a bit disconcerting, so I prefer tosimply work from s separate project that is already checked out from the HEAD branch.

You might consider placing a “tag” on the main branch (HEAD) to mark the spot on the branch just prior to the merge. that way, if you make amistake when resolving conflicts (see below), it will be easy to get back to the current version. To place a tag, right-click on a project with an up-to-date copy of the HEAD, and select “Team ⇒ Tag as Version … ”

2: Right-click on the HEAD project and select “Team ⇒ Merge … ”.

You will be asked what branch you want to merge with. Select the appropriate branch to be merged into HEAD.You will be asked to supply the common base version from which the branch was split - usually Eclipse will guess this correctly.You can also decide whether to have CVS automatically make any non-conflicting changes or to let you preview them.No matter what choice you make here, conflicts will still be presented to you for resolution.

3: CVS will compare the checked-in copy of the branch against the files in your local HEAD project.

You should see the familiar Synchronization view, in which you can preview changes and resolve conflicts.The goal of this process is to leave you with a local copy of all the desired changes.

This is not a commit of the merged changes to the HEAD branch.

4: Having resolved all changes, you now have a local copy of the project, associated with the HEAD branch in CVS, with a merged copy of code from theformer HEAD and from the other branch.

It has not been committed to the repository yet.You can test it out, and then decide whether to commit the changes into the HEAD.

1.3 CollaborationResolving Conflicts

During synchronization, changes are categorized as

Incoming: files that you have not edited your local copy (since it was last synchronized with the repository) but for which a revision has since beenchecked in.

These presumably need to be updated.

Outgoing: files that you have changed (since it was last synchronized with the repository) and for which no revisions have been checked in.

These presumably need to be committed.

Page 336: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Conflicts: Files that have been changed in your local directory and that have had revisions checked in to the repository.

These presumably need to be merged

The Conflict Editor

Eclipse has a built-in conflict editor tohelp merge conflicting versions.

It allows you to view thedifferences between the twoversions and decide whether

to keep the local version ofeach block of changedlines orto replace by therepository’s version.

You can save the merged file andthen “Mark as Merged”, whichmoves it from the “Conflicts”status to “Outgoing”

Or you can “Override andUpdate”, which indicates thatyou are abandoning your localchanges and changing the file’sstatus to “Incoming”

2 SubversionSubversion

Subversion (a.k.a. svn) is a later version control system based on the same centralized model as CVS.

For the most part, working with it is not all that different from CVS.

It rose to popularity in the open source community in part because of some useful tools for making read-only versions available on the web.

Page 337: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

In fairness, this is not due to any particular strength of Subversion.Such tools could easily be targeted at CVS as well.

2.1 HistoryDifferences between CVS and Subversion w.r.t. history:

Subversion uses simpler revision numbers

Subversion tracks file and directory creation, deletion, renaming

2.2 Exploration

2.2.1 Subversion Doesn’t Understand Branches …

Subversion does not implement a distinct mechanism for branching.

Each revision (and each checked-out local copy) “knows” its parent revision number.

Revisions can be checked out into distinct local directories from where their parents were located.

Remember – Subversion tracks moving/renaming of files

… but it Does Branches Anyway

A typical subversion repository looks like this.

“Branches” are kept in a separate directory from the trunk.

But a checked-out version of a branch “knows” which revision it came fromwhether that revision is on the trunk or on the branch

“Merging” is a general operation between revisions

So it can be done as a regular merge to adopt changes made in the branch as part of the trunkor as a “sync merge” to add revisions from the trunk to the branch

Page 338: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Is This an Improvement?

I can’t decide if Subversion’s approach to branches is inspired or lazy.

The two are not, of course, mutually exclusive.

Page 339: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Branching and merging is CVS is just complicated enough that it’s easy to mess up.

Luckily, you can always recover from mistakes by checking out an older version and re-committing.

In svn, you typically check out the trunk or a branch – not the whole repository.

2.2.2 Subversion Doesn’t Understand Tags …

… but it does tags anyway, the same way it does branches.

Tag name becomes the folder name within the Tags directory.

Page 340: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.3 CollaborationNo real differences between CVS and SVN

Conflicts can arise a check in and must be manually resolved.

Page 341: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.4 Eclipse IntegrationNot part of the regular distrbution

has to be installed as a plug-in

Two plugins are availableSubversion is older and is an “incubating” part of the Eclipse project

But has been in that status for a long timeSubclipse is newer, seems to be more aggressively updated

Installation can be somewhat tricky (on Linux, at least)

Relies on some non-Eclipse libraries that must be installed separately.

Sometimes a period of instability after Eclipse updates before either plugin becomes usable.

Google for instructions on either plugin

Page 342: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Distributed Version ControlSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 git

1.1 Where do files live?1.2 Revisions1.3 History1.4 Exploration

2 Collaboration3 Eclipse Integration

Abstract

Distributed version controls models relax the dependency upon a central repository as the keeper of the one true project.

Every developer has a snapshot of an entire development history.

In essence, you check out the entire past history of a project.And every checked out copy becomes an independent branch.

Developers may decide for themselves which of these branches should merge

Merging and conflict resolution, which are treated as exceptional operations in centralized systems, are regarded as the norm in this model.

We will look at git, a popular distributed version control system.

Sounds Like Anarchy

In practice, projects often due have a central repository for “official” releases.

But splinter projects are easier to form

and can continue to share some changes until the code base diverges too much.

Page 343: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A Synthesis of Local and Remote

In a distributed model, a developer maintains

a local repository

into which changes can be committed (as in local models like rcs)

and periodically may synchronize with a remote repository

which might be centralized or just another developer’s

Two-Level Commits

The local/remote division helps resolve a common dilemma in centralized VC systems:

When or how often should we commit changes?In a centralized system, we have conflicting goals

Safeguard against losing work: argues for committing frequentlyAvoid interfering with other developers by not checking in incomplete work

A newly checked-out copy should always compile and yield a (roughly) working product.

a.k.a., “Don’t break the build!”

In a two-level system, we can commit frequently to the local repository and only when a “unit” of work is completed, commit to the remote repository.

Matthew McCullough’s tongue-in-cheek critique: Please. Stop using Git.

1 git1.1 Where do files live?

Edit files in your work area

Your ordinary directories/folders of files

Stage the files that you want to commit.

Page 344: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The stage is also sometimes called the index.

A commit copies updates the local repository withthe files on the stage.

Push sends commits from your local repo to aremote one.

Pull fetches commits from the remote repo into yourlocal one.

If safe, merges changes into your work area aswell.

1.2 RevisionsUnlike earlier VC systems, a git revision is a state of the entire project rather than of a single file/directory.

After committing a change, the entire system, even unchanged files, advance to a new revision IDOf course, “behind the curtain” you are still going to have incremental diffs, but that does not affect our visible interactions

Because of the distributed model,

revision numbers cannot simply be incremented in any meaningful fashionthere is a need to easily determine when two revisions in two different repositories are, in fact, copies of the same system state

Revision numbers are therefore replaced by hash codes computed over the file set that constitutes the entire project

git Snapshots

A git repository contains, conceptually, a collection of snapshots (a.k.a., commit objects, a.k.a. revisions, a.k.a. versions).

Each snapshot contains

The set of files for the project

The name of this snapshot (hash code)

References to the parent snapshots

Page 345: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Most have one parentInitial commit would have zeroMerges can result in a snapshot with multipel parents

Heads

A git repository also contains a collection of heads.

These are human-assigned names for selected snapshots.

Heads refer to the most recent snapshot in a chain of commits

Hence heads actually identify branches

Every repository has a head “master”.

At any given time, one head is considered active. This one is aliased tothe head “HEAD”.

How shall I name thee?

Snapshots in a repository may be identified by giving

Its SHA1 hashcode

A long enough prefix of that hashcode to be unique

By a head

Relative to one of these: ^ means “parent-of”

e.g., HEAD^ would be the state before our most recent commit

1.3 History

Page 346: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Common Local History Commands

git add files stages modified files, scheduling the current version to be included in thenext commit (recursing through directories)

An intermediate step not needed in earlier VC systems

git commit -m message commits all staged changes to the local respository

Add a -a to add all modified files in the current directory and below to the stagingset

git status lists modified files

git diff file displays what was changed

1.4 ExplorationEvery Local Repository is a Branch

So one way to “branch” in git is to simply check out a new copy.

But sometimes we want to branch within a local repository

Branching Within a Local Repository

git branch newHeadName/*-i desiredParentSnapshot

creates a new branch

git checkout branchHead

switches to a new branch

Replaces the files in the current directory by a copy of the state for that branch.

When Should I Commit? (Another perspective)

git users consider branches to be cheap.

So some advocate

Page 347: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Always work in branches

Keep the master branch in a releasable state

Remember, every local copy of the repository a branch in its own right. So one way to achieve the same effect is to commit frequently in your local repositorybut only push to the central repository when you have something in a releasable state.

This approach delays making your unfinished code available to other members of your team. Whether this is a viable approach depends on

Whether your local repository is backed up.

The chances of other team members making conflicting changes.

The longer you go between pushes and pulls, the more likely you are to encounter merge conflicts and the harder they will be to resolve.

Merging Local Branches

git merge head

produces a new snapshot representing the merge of the current one (HEAD) with the named head.

The merged revision will have both HEAD and head as parents.

git identifies the more recent common ancestor of the two branches and performs a 3-way mergeIf a change (compared to the common ancestor) does not conflict (overlap) any changes from the other branch, the change is copiedautomatically into the merged state.If conflicts are determined, markers are inserted into the working copy of the file and the user alerted.

If the merge completes without conflict, the resulting merged state is committed.If conflicts were found, the working copy is updated but no commit takes place.

Branches not needed after a merge can be deleted

git branch -d head removes the head name from the repository (but does not actually delete the history of changes along the branch.

2 CollaborationCollaboration in git takes the form of interaction between your local repository and a remote repository.

Concepts (and, sometimes, commands) are much the same as in the local mode

Page 348: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Starting from a Remote Repository

If you are working with an existing remote repository

git clone remoteSpec

creates a new local repository as a copy of the remote one.

The remoteSpec names the remote repositoryCould be a simple file path if on the same machineCould be an http:// URL (generally for anonymous access)Could be an ssh address

Cloning

Suppose that we have a remote repository with two branches and a few commitobjects on each.

Our local cloned repository will remember its remote origin repository.

All heads from the remote repository will be cloned as origin/head

We will get a local master head

You can request local heads for non-master branches by tracking, e.g.

Page 349: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

git branch --track enhanced origin/enhanced

Life after Cloning

Starting from this local repository, …

Page 350: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

… suppose each repository adds a commit along the trunk:

Our local heads separate from the remembered positions of the remote ones.

Page 351: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Fetching Remote Changes

The basic command to get changes from the remote repository is git fetch

Page 352: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Remember, each repository is, in essence, a new (set of) branch(es)

If states are not identical, they are fetched as new branches

Local heads are unaffected

Pulling Remote Changes

More commonly used than fetching is pulling, which combines a fetch and a merge

Page 353: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Starting with this remote repository…

…and this local one.

(Note that commits (F, G) have been made to both repositories since the clone wascreated.)

Then

git pull origin master

yields this new version of the local:

Page 354: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Pushing to the Remote Repository

The push command

sends local commits to a remote repository

Advances the remote head marker to the end of the list of changes.

If the remote repository looks like this

and our local repository looks like this

Page 355: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

git push origin master

yields this remote repository.

Push is NOT the Opposite of Pull

It’s actually the opposite of fetch

No merge is done when pushing

This leads to an important restriction

The remote head must point, before a push, to an ancestor of the commit that it would point to after the push.

Page 356: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

This Push Will Fail

If the remote repository looks like this

and our local repository looks like this,

the push will fail

because if it went through, we would lose access to a state already committed in the remote repository.

Page 357: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance
Page 358: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Avoiding Bad Pushes

Easiest thing to do is to do a pull into the local repository first, then do the push.

And hope no one sneaks in ahead of you

An alternative is rebasing

Rebasing

Rebasing changes the parent relationship of the current head so that it appears to have been derived directly from some other selected head.

If we start with this and do

git rebase master

Page 359: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

we get this.

Now looks like enhanced was derived directly from the master head.

The Perils of Rebasing

For all the talk about rebasing in the git literature, you would think it was a very common operation.

But,

rebasing loses information

with usually very little savings in storage

done at the wrong time, can make pushing to a remote server much harder

Why Rebase?

Page 360: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Generally recommended only for

Managing an unshared branch that you want to keep up to date with the master and don’t care if you lose history.

Recovering from a failed push when someone else sneaks in between your pull and your subsequent push.

You fetch their changesThen rebase your head to appear as if it were derived from their head.You can then push, because you have guaranteed that the remote head is an ancestor of yours

Unless someone else sneaks in yet another push while you are doing the rebase.

Isn’t distributed access fun?!

Page 361: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3 Eclipse IntegrationThe (Egit) plugin integrates git into Eclipse.

Egit has recently been incorporated into the Eclipse main update/plugin distribution site.Help is available within Eclipse, or from the reference manual on the Library page.

Operation is similar to the CVS and SVN plugins, except that

The Team menu gains new commands to push and pull.

There is no New ... Project from Git option.

Instead, use the Import menu.

A typical work session using egit

Eclipse, git, and a Forge

New projects:

1. A Forge environment will create an empty repository

2. Use the Git Repository Exploring perspective to clone the repository .

Store it outside your normal Eclipse workspace.

3. Create a directory to hold the project as a sibling of the .git directory you have just obtained.

Put at least one file of content (e.g., a build.xml file) in that directory.

4. In Eclipse, do File ⇒ Import and select Git. Follow the instructions to name your local repository that you just cloned and “Use New Project Wizard”.

5. When the regular project wizard starts, direct it to your project folder you created in step 3.

6. After the new project wizard is completed, Eclipse still will not show the project as managed by Git.

Use Team ⇒ Share project .... You’ll be asked what repository to use. Let Eclipse try to find it. (It should be able to do so).

7. Use Team ⇒ Add to index to add files to version control.

Page 362: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

8. Team ⇒ Commit (or Synchronize).

9. Team ⇒ Push.

Existing Projects

1. A Forge environment will contain instructions/settings on how to access the existing repository

2. Use the Git Repository Exploring perspective to clone the repository.

Store it outside your normal Eclipse workspace.

3. In Eclipse, do

Create a new Java project, outside of the default workspace location. For the location, navigate to your newly created copy of the project directory,within the directory where you cloned the git repository.Or, for non-Java projects, File ⇒ Import and select Git. Follow the instructions to name your local repository that you just cloned and use the NewProject Wizard .

When the regular project wizard starts, direct it to your project folder you created in step 3.

4. After the new project wizard is completed, Eclipse might not show the project as being managed by Git.

Use Team ⇒ Share project .... You’ll be asked what repository to use. Let Eclipse try to find it. (It should be able to do so).

5. Use Team ⇒ Add to index to add files to version control.

6. Team ⇒ Commit (or Synchronize).

7. Team ⇒ Push.

Page 363: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

from The System

Page 364: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Lab: Version Control with GitSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Gitting Started

1.1 Fetching changes1.2 Committing changes

2 Coping with Conflict3 Finishing Up

This is a self-assessment activity to give you practice in working with the git version control system. Feel free to share your problems, experiences, andchoices in the Forum.

1 Gitting Started1. Current versions of Eclipse have the Eclipse plugin for Git already installed. Take a moment and browse the EGit User Guide.

2. Open an ssh session on one of the CS Linux servers. Give the command

~zeil/Assignments/cs350/gitLab/step1

You will be given the URI of a git repository.

3. Fire up your installation of Eclipse. Go to Window ⇒ Open perspective... and open the Git perspective. Move your mouse across the controls at the topof the Git repositories view and select “Clone a git repository…”. Enter the URI that you were given. Fill in your user name, but leave the passwordblank.

Click through Next and Finish to complete the clone. As you do, take note of the directory in which your repository is being stored. (You can change thisto something more convenient if you like.)

Look in your git repository folder. You should see that a new directory has been added. Look in that directory (use -a on Linux). You will see that itcontains a .git directory, which is where the version control info is kept, and a directory for the real project.

Page 365: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4. In Eclipse, return to the Java perspective. (You can do this from Window ⇒ Open perspective... or by using the shortcut perspective button in the upperright corner of the Eclipse window.)

Follow the usual procedure for creating a new Java project, but instead of the default project location, select that project directory (the one containing thepastry directory).

5. Look around in the project. try compiling and running it. Don’t make any changes yet.

1.1 Fetching changes1. Back in your ssh session, give the command

~zeil/Assignments/cs350/gitLab/step2

This is simulating someone else on your team working on the same project.

2. In Eclipse, right-click on your project and select Compare with... ⇒ HEAD revision. This compares against the most recent check-in to your local copyof the repository. Since you have not made any changes yet, you should not see much of anything, maybe a few new files created when you compiled.

3. Now try Compare with... ⇒ branch, tag, … Select “Remote tracking” and then “master”. This compares against the remote repository, and youshould be able to see that your mysterious teammate has checked in some changes.

In the synchronization view, find the file that has changed and double-click on it to open up the comparison editor.

4. Most of the version control commands are accessed by right-clicking on the project and looking under the Team menu item. Return to the Java perspectiveand use that to pull the changes from the remote repository.

1.2 Committing changes1. Try making some simple changes, such as editing some of the comments in the source code.

2. From the Team menu item, commit your changes. As you examine the “commit” dialog, you will see that you have the option of doing a simple localcommit or of doing a commit followed by an immediate push to the remote repository. Go ahead and push.

2 Coping with Conflict1. Back in your ssh session, give the command

~zeil/Assignments/cs350/gitLab/step3

Page 366: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2. In your Eclipse session, refactor the Pie.getBaseColor and Pie.setBaseColor functions, renaming them to getBackgroundColor and setBackgroundColor.

(By using the “refactor” menu, you get all calls to that function to be changed at the same time, even calls in other .java files.)

3. Now try to commit and push your changes. The commit should work, but the push fails because your mysterious teammate has already checked in somemore changes to the project.

4. See if you can resolve this conflict and eventually commit and push a combination of your changes and those of your teammate. You will need to

fetch the changes from the remote repository,force a merge between your local HEAD revision and the remote’s “master” head, if that doesn’t happen when you fetch the changes

Although Eclipse and git will be able to handle the merge in some files automatically, they will not be able to handle all of them, becausethere are some lines in one file that have been changed by both you and your simulated teammate.

Use the Eclipse conflict editor to combine the changes between the opposing versions of the conflicted file.“Add” the resolved file back into the index as a signal that you are satisfied that the conflict has been resolved.Commit and push the change again.

3 Finishing UpThe remote repository for this lab was stored in your Linux account as ~/.cs350gitlab.

To clean up after the lab (or to reset to the beginning if you want to start it over from the beginning), do

rm -rf ~/.cs350gitlab

While you still have those keys handy, now would be a good time to go to the course forge, log in to GitLab. Go to your Profile settings, select “SSH Keys”,and add your public key. This is how GitLab will know that your Eclipse IDE is allowed to work with your project. (Remember, you have already told Eclipseabout the location of your private key. So, between the two of them, they have enough information to validate your credentials.)

Page 367: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

ForgesSteven J Zeil

Last modified: Sep 14, 2017

Contents:

Abstract

A software forge is a collection of web services for the support of collaborative software development:

Project web sites

Networked access to version control

Release (download) support

Communications (e.g., messaging, wikis, announcements)

Bug reporting and tracking

Project personnel management

In this lesson, we will look briefly at some popular forges and then will explore the forge specifically constructed for your use in this course.

Forge Examples

Among the best known forges are

the original, SourceForge, (1999)

Google Code, (2006)

GitHub, (2008)

The CS 350 course has its own forge

GitLab for project management, version control, issue tracking, wiki

Page 368: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Jenkins for continuous integrationRedmine issue tracking

Page 369: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Build ManagersSteven J Zeil

Last modified: Mar 2, 2020

Contents:1 Some Sample Project Builds

1.1 Student Programming Assignment1.2 Code Annotation Tool1.3 Class Assignment Setup1.4 Posting Slides and Lecture Notes

2 Structural Architecture of a Development Project2.1 Projects and Sub-projects2.2 The Project Directory2.3 Sub-Project Directory (Java)2.4 Sub-Project Directory (C/C++)

3 Types of Build Managers3.1 IDE project managers3.2 Dependency-Based Managers3.3 Task-Based Managers

Abstract

A build manager is a tool for scripting the automated steps required to produce a software artifact.

We will start this module by looking at what types of services we would like to obtain from build managers.

These will be motivated by looking at some sample projects to consider the steps required to build them. An important lesson will be that builds often involvemore that the “obvious” reuqirement of compiling and linking the code.

We will then survey some of the options for build managers, including scripting, IDE project managers, and dependency-based and task-based buildmanagement tools.

What Should a Build Manager Do?

A good build manager should be

Page 370: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

easy to use

easy to set up for a given project

efficient in performing the build

avoid redundant/unnecessary actionsdetect and abort bad builds in progress

incremental

allow focused/partial builds

flexible

allow for a variety of build actionson a variety of platforms

configurable

permit the management of multiple artifact configurations

1 Some Sample Project BuildsHere are some of the project builds I have had to automate in the opening weeks of one semester:

1.1 Student Programming AssignmentSet up to allow students to easily compile code for an assignment.

Build each missing or out-of-date .o file by compiling a corresponding .cpp file.

Record which .cpp files and .h files were used during the compilation so that future builds can determine what would future source code changeswould make this .o file outdated.

Link all .o files to produce an executable

1.2 Code Annotation ToolThe code annotation tool is a program I use to convert C++ and Java code with optional markup comments like this into this.

Page 371: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Building the Code Annotation Tool

The steps involved in building this tool are:

1. Run the program jflex on each file in src/main/jflex, generating a pair of .java files that get placed in src/main/java

2. Compile the Java files in src/main/java, placing the results in target/classes

3. Compile the Java files in src/test/java (using the target/classes compilation results, placing the results in target/test-classes.

4. Run the JUnit tests in target/test-classes.

5. If all tests pass, package the compiled classes in target/classes into a .jar file.

It’s worth noting how many of the steps in this project build are not simply compile and link steps.

1.3 Class Assignment SetupClass Assignment Setup

In preparing to release a programming assignment to a class, the steps are

1. Setup:

Copy all of the files that I will provide to students from a Public directory into a Work directory.Copy all of the files from my Solution directory into that Work directory

2. Build solution

Compile any .cpp files in the Work directoryLink the resulting .o files.

3. Run the executable produced in the last step on each test*.dat in the Tests directory, capturing the output as a corresponding .out file.

4. Copy all source code from the Work directory into a winWork directory.

5. Use a cross-compiler to compile and link the .cpp files in winWork into a Windows executable

6. Install:

Copy the two executables and the contents of the Public directory into a release area accessible to students.Set the permissions on the copied files so that they can be accessed.

Page 372: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Copy any .html and graphics files for the assignment to the course website.

1.4 Posting Slides and Lecture NotesThe lectures notes for this course are prepared through a process:

1. Setup

Convert all graphics to PNG or PDF:For each GIF file in the directory with no corresponding PNG file, run convert to produce a PNG.For each FIG file in the directory with no corresponding EPS file, run fig2dev to produce an EPS.For each Dia file in the directory with no corresponding EPS file, run dia to export as EPS.For each EPS file in the directory with no corresponding PDF file, run epstopdf to create a PDF. \eii Annotate source code:For each C++ or Java file with no corresponding HTML file, use the code annotation tool to generate an HTML file.For each C++ or Java file with no corresponding TeX file, use the code annotation tool to generate an TeX file.

2. Generation: For each desired document output format,

Run a preprecessor on the markdown file containing the document source.Run a markdown processor to generate HTML.Apply an XSLT stylesheet to add format info and to split the document into slides/pages.

3. Deployment:

Synchronize this directory with the corresponding directory of the website, orPrepare a zip file with the contents of this directory that can be uploaded to a remote webserver (e.g., Blackboard).

2 Structural Architecture of a Development ProjectLet’s talk about how development projects are typically organized into files, directories, etc.

2.1 Projects and Sub-projectsA project consists of one or more more sub-projects.

Even if we conceive of a project as a single entity, it’s worth treating it as having a single sub-projectA hedge against changing our minds later.Sets a standard for consistent tool use and setup

Page 373: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What Constitutes a Sub-project?

A sub-project is generally defined as the code and data that yields a single deliverable.

Examples of deliverables include

an executable programa library

Java .jar orC/C++ .a, .lib, .so, or .dll

a reference manual

Example: The AlgAE project has sub-projects

sub-project deliverablealgae-client-server algae-4.1.jar

algae-cppserver libalgaecpp.a

algae-referenceManual referenceManual.pdf

demos/FordToppBST FordToppBST.zip

demos/ReferenceManualJava algae-jrefman.jar

Why divide a project into multiple sub-projects rather than into multiple smaller independent projects?

The entire project is stored in a single location/repository.

The entire project can be built with a single command.

The entire project can share certain configuration data.Sub-projects may be more tightly coupled than would be desired of independent projects.

2.2 The Project DirectoryTypically contains

Top-level project documentation.Overall project build & configuration informationOne sub-directory per sub-projectVersion control and configuration management information

Page 374: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.2.1 Example: AlgAE

Top-level directory contains:

README.md, LICENSE.mdbuild.xml: builds the sub-projects in the correct order.git, .gitignore, ivysettings.xml (version control and configuration management)Directories:

algae-client-serveralgae-cppserveralgae-reference-manualdemosReports

All but the last are sub-projects.

C/C++ projects might add directories that will (after the project is built) contain the various sub-projects’ deliverables:

binlib

2.3 Sub-Project Directory (Java)Contains:

sub-project build & configurationsource code directoryproject and test datatarget directory for deliverables and other build projects

When source code is compiled, output is placed here rather than in the source code directory

2.3.1 Apache Project Directories

The Apache Foundation hosts many open source projects, which organize their projects & sub-projects like this:

src/ # anything supplied/edited by the programmers target/ # initially empty, holds products of the compilation/build

The src/ directory is split into separate directories for the "real’ code and for the test code.

Page 375: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

src/ | main/ # things that contribute directly to the deliverable | test/ # things used for testing but not delivered target/

“Deliverables” are usually an archive of some kind.

If the project is supposed to produce a Java application or a Java library, the deliverable is usually packaged in a Jar.

Server-side web applications are delivered in a War or an Ear.

Source code is sometimes packaged in a Jar, but more often in a Zip. (Usually, though, when we talk about deliverables in this section, we’ree referring to“binary” deliverables.)

Android apps are packaged in an APK.

The division of the source files into separate main/ and test/ makes it easier to eventually construct those deliverable archives because we won’t treat entiredirectories worth of stuff uniformly, rather than having to select desired materials on a file-by-file basis.

src/main/ is further subdivided:

src/ | main/ | | java/ # Java source code, compiled into target/classes | | resources/ # data files that will be included in the deliverable archive | | data/ # data files required during build but not part of deliverable | test/ target/ | classes/ # data and compiled code that are packed into the .jar deliverable | project.jar # the deliverable

(These directories can be omitted if they are empty.)

Java libraries and applications can read data from files within their own distribution archive with only slightly more difficulty than reading from an ordinaryfile. To do so, the Java code is written to search the Java CLASSPATH, the same path used to hunt for the compiled Java code.

They cannot, however, write to those data files. The data access is read-only.

The src/test/ directory is split in an analogous fashion:

src/ | main/

Page 376: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

| | java/ | | resources/ | | data/ | test/ | | java/ # Java source code, compiled into target/test-classes | | resources/ # data files, available during testing via CLASSPATH | | data/ # test data target/ | classes/ | test-classes/ # data and compiled code for unit testing | project.jar

Test resources are intended to be accessible during testing via the code already written for accessing main (deliverable) resources. One way to support this is tocopy the src/test/resources contents into target/test-classes, so that the same CLASSPATH-based mechanisms to locate the compiled test code will alsofind the test resources.

2.3.2 Android/Gradle Project Directories

A similar directory structure is employed for Android projects. The Gradle build manager, which we will cover later in this section, has made the Androidstructure its default for Java projects, making it a popular organization for non-Apache projects.

The most obvious difference is that the products of the build are stored in build instead of target.

src/ # anything supplied/edited by the programmers build/ # initially empty, holds products of the compilation/build

The src/ directory is laid out identically to the Apache organization:

src/ | main/ | | java/ # Java source code. After compilation, is part of the deliverable. | | resources/ # Data files that will be included in the deliverable, accessible via CLASSPATH | | data/ # Data files needed for the build, but not part of the deliverable. | test/ | | java/ # Java source code for testing, will not be part of the deliverable | | resources/ # data files, available during testing via CLASSPATH | | data/ # test data build/

The build directory, however, has a more detailed breackdown than in the Apache project:

src/ | main/ | | java/ # Java source code. After compilation, is part of the deliverable. | | resources/ # Data files that will be included in the deliverable, accessible via CLASSPATH

Page 377: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

| | data/ # Data files needed for the build, but not part of the deliverable. | test/ | | java/ # Java source code for testing, will not be part of the deliverable | | resources/ # data files, available during testing via CLASSPATH | | data/ # test data build/ | classes/ # Compiled code | | main/ # Compiled code from src/main/java/, will be part of the deliverable | | test/ # Compiled code from src/test/java/, will not be part of the deliverable | | libs/ # Deliverables are placed here. | | reports/ # Generated reports including documentation, test coverage, analysis, etc. | | test-results/ # Outputs from testing | | tmp/ # Work area for general temporary files

2.3.3 Variations

Additional files and directories in target/ are common.

I usually have a target/reports/ directory for testing and other report generated during the build.If my tests need to produce output files, I usually try to put those in target/test-outputs (so they can be easily cleaned up)

Analogous to main/java and test/java, we can have directories for source code in other programming languages.

For example, the code annotation project has source code in jflex, which actually is compiled to produce Jave code in target/gen-source/,which is then itself compiled into target/classes.

src/ # anything supplied/edited by the programmers | main/ # things that contribute directly to the deliverable | | java/ # Java source code, compiled into target/classes | | jflex/ # JFlex source code, compiled into target/gen-source | | resources/ # data files, copied into `target/classes` | | data/ # data files required during build but not part of deliverable | test/ # things used for testing but not delivered | | java/ # Java source code, compiled into target/test-classes | | resources/ # data files, copied into `target/test-classes` | | data/ # test data target/ # initially empty, holds products of the compilation/build | classes/ # data and compiled code that are packed into the .jar deliverable | gen-source/ # automatically generated Java source, compiled into target/classes | test-classes/ # data and compiled code for unit testing | project.jar # the deliverable

Later in a project, I might add separate src/ and target/ subdirectories for integration & system testing.

Page 378: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Example: see this structure in the Code Annotation project

2.4 Sub-Project Directory (C/C++)Much more variation exists. One possibility is:

include/ # header files | src/ # compilation units (.c and .cpp files) | bin/ # executables and .o files produced by compiling src/ | lib/ # libraries produced by combining object files

Sometimes .o files are placed in a separate obj/ directory.Sometimes executables and libraries are copied directly to a project-level bin/ or lib/ directory.

2.4.1 Android-ish structure

Increasingly common is this approach, inspired by the Apache/Android Java styles:

src/ | main/ | | cpp/ # C++ source code. .cpp files and local headers | | headers/ # Header (.h) files that need to be visible to main code and | | # to tests. | | public/ # For library projects, the header files that will be exported | | # as part of the delivered library. | test/ | | cpp/ # Unit test code | | data/ # test data build/ | exe/ # Executables | | main/ # - from main/cpp | | test/ # - from test/cpp | lib/ # libraries constructed from object code | | main/ # - from obl/main | obj/ # Compiled object code | | main/ # - from main/cpp | | test/ # - from test/cpp | tmp/ # Work area for general temporary files

Page 379: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3 Types of Build Managers

Why Not Just Write a Script?

We could simply write a “simple” script to perform each of the steps in sequence …

#!/bin/sh cp Public/* Work/ cp -f Solution/* Work/ g++ -o Work/program Work/*.cpp find Tests -name 'test*.dat' -exec sh runTest.sh Work/program {} \; mkdir WinWork cp Work/*.h Work/*.cpp WinWork x86_64-w64-mingw32-g++ -o WinWork/program WinWork/*.cpp --static mkdir $releaseDir/bin mkdir $releaseDir/bin/Linux cp Work/program $releaseDir/bin/Linux mkdir $releaseDir/bin/Windows cp WinWork/program $releaseDir/bin/Windows chmod 775 $releaseDir/bin/*/program cp *.html *.png $website/

Scripting

But how does this fare according to our earlier build manager goals?

easy to use? Y

easy to set up for a given project? N

efficient in performing the build?

avoid redundant/unnecessary actions N

detect and abort bad builds in progress ?

incremental?

allow focused/partial builds ?

flexible?

Page 380: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

allow for a variety of build actions N

on a variety of platforms N

configurable?

permit the management of multiple artifact configurations ?

3.1 IDE project managersMost IDEs come with a built-in project manager.

typically limited to compiling and linking

maybe some support for packaging

3.2 Dependency-Based Managers Some build managers are based on the idea of a dependency graph:

Boxes are files.

Arrows denote dependencies. “A depends on B” means that if B ismissing or changed, then A must be (re)generated.

Labels on arrows indicate the program used to generate the file at thebase of the arrow.

Analysis of such a graph facilitates

efficiency - easy to tell what needs to be rebuilt after a change

incrementality - can determine required build step for any file, not justthe “final” one

make is the canonical example of a build manager of this type.

3.3 Task-Based Managers

Page 381: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Other managers are based on the idea of interdependent tasks.

Ellipses are tasks (activities). Each task can involve multiple steps.

Arrows denote success dependencies. “A depends on B” means that Awill be run after B and only if task B finished successfully.

This approach facilitates

ease of setup: usually less detailed than a full file-based dependencygraph

incrementality - can request any intermediate step

ant is based on this approach.

Page 382: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

File Dependencies: makeSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 The make Command2 makefiles

2.1 Rules2.2 Variables2.3 Implicit Rules and Patterns

3 Working with Make3.1 Touching Files3.2 Artificial Targets3.3 Dependency Analysis3.4 Managing Subproject Builds

4 Case Studies – Introduction4.1 Simple Java Build4.2 Java Build with Code Generation4.3 C++ Multi-project Build

5 Case Studies – Makefiles5.1 Simple Java Build – Makefiles5.2 Java Build with Code Generation – Makefile5.3 C++ Multi-project Build – Makefiles

Abstract

make is perhaps the oldest build management tool. It introduced the idea of dependency-based builds.

In this lesson we will look at the build model implemented by make and at how to describe projects to the make tool.

We will look at how make could be applied to some of our sample projects from the prior lesson.

make

make is a command/program that enacts builds according to a dependency graph expressed in a makefile.

Page 383: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

make devised by Dr. Stuart Feldman of Bel Labs in 1977

It has long been a standard component of *nix systems

GNU make is a popular moden variant

1 The make Command

make looks for its instructions in a file named, by default, makefile orMakefile

The make command can name any file in the graph as the target to bebuilt, e.g.,

make CppJavaScanner

If no target is given, make builds the first file described in the makefile

make Options

Some useful options:

-nPrint the commands that make would issue to rebuild the target, but don’t actually perform the commands.

-k“Keep going.” Don’t stop the build at the first failue, but continue building any required targets that do not depend on the one whose construction hasfailed.

-f filenameUse filename instead of the default makefile or Makefile

Page 384: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2 makefilesAt its heart, a makefile is a collection of rules.

2.1 RulesA rule describes how to build a single file of the project.

Each rule indicates

The target file to be constructedThe dependencies: the other files in this project from which the target is constructed.The commands that must be executed to construct the target from its dependencies.

Rules may appear in any order

Except that the first rule’s target is the default built by make when no explicit target is specified in the command line.

The Components of a Rule

A rule has the form

target: dependencies commands

where

target is the target file,

dependencies is a space-separated list of files on which the target is dependent

commands is a set of zero or more commands, one per line, each preceded by a Tab character.

Rule Examples

codeAnnotation.jar: code2HTML.class CppJavaScanner.class jar tvf codeAnnotation.jar code2HTML.class CppJavaScanner.class

Page 385: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

CppJavaScanner.class: CppJavaScanner.java javac CppJavaScanner.java code2HTML.class: code2HTML.java CppJavaScanner.java javac code2HTML.java CppJavaScanner.java: code2html.flex java -cp JFlex.jar JFlex.Main code2html.flex

Why is This Better than Scripting?

Suppose that we edit code2html.java and then invoke make

Only one javac will be issued, after which the jar command is run.

make has determined the minimum number of steps required to rebuild after a change.

How make Works

Construct the dependency graph from the target and dependency entries in the makefile

Do a topological sort to determine an order in which to construct targets.

Page 386: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

For each target visited, invoke the commands if the target file does not exist or if any dependency file is newer

Relies on file modification dates

2.2 VariablesA makefile can use variables to simplify the rules or to add flexibility in configuring the makefile.

All variables hold strings.

Variables are initialized by a simple assignment

variable = value

Variables are immutable (constants)

Assignments may appear within the makefile or in the command line, e.g.:

make JOPTIONS=-g codeAnnotation.jar

Referencing Variables

Variables are referenced as $(variable) or ${variable}, e.g.,

CppJavaScanner.class: CppJavaScanner.java javac $(JOPTIONS) CppJavaScanner.java code2HTML.class: code2HTML.java CppJavaScanner.java javac $(JOPTIONS) code2HTML.java

Adding Power to Variables

GNU make adds some special extensions useful in setting up variables.

Globbing:

SOURCEFILES=$(wildcard src/*.cpp)

Page 387: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

collects a list of all C++ compilation units in the filename{src} directory

Substitutions:

OBJFILES=$(SOURCEFILES:%.cpp=%.o)

collects a list of all object code files expected by compiling those compilation units.

Example: Using variables

This allows us to write a “generic” rule for compiling C++ programs:

PROGRAM=myProgramName SOURCEFILES=$(wildcard src/*.cpp) OBJFILES=$(SOURCEFILES:%.cpp=%.o) $(PROGRAM): $(OBJFILES) g++ -o $(PROGRAM) $(OBJFILES)

This is technically, incomplete.

We have not explained how to produce a .o file from a .cpp

Nonetheless, it would work on some systems for the initial build, because they have an “implicit” rule for working with C++

Still not a good solution by itself – dependencies on .h files have not been captured.

2.3 Implicit Rules and PatternsImplicit rules describe how to produce a single “kind” (extension) of file from another.

All make implementations will have some common implicit rules.You can modify the list of implicit rules.

Pattern rules are a GNU extension for writing “generic” rules

Implicit rules could, for the msot part, be written as patternsBut patterns offer some additional flexibility

Page 388: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Implicit Rules

An implicit rule looks like

.ext1.ext2: commands

where ext1 and ext2 are file extensions, and commands are the commands used to convert a file with the first extension into a file wit hthe second.

Example:

.cpp.o: g++ -g -c $<

the implicit variable $< holds the dependency file

Also commonly used, $@ denotes the target file.

Using Implicit Rules

The extensions used in implicit rules must be declared:

.SUFFIXES: .cpp .o

An implicit rule will be used when a target ends in one of these suffixes and

there is no rule listing that file as a target, or

the rule listing that file as a target has no commands

Implicit Rule Example

PROGRAM=myProgramName SOURCEFILES=src/main.cpp src/adt.cpp OBJFILES=$(SOURCEFILES:%.cpp=%.o) .SUFFIXES: .cpp .o .cpp.o:

Page 389: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

g++ -g -c $< $(PROGRAM): $(OBJFILES) g++ -o $(PROGRAM) $(OBJFILES) src/adt.o: adt.cpp adt.h

Both main.cpp and adt.cpp will be compiled on the initial build.

If adt.h is subsequently modified, then adt.cpp would be re-compiled.

Pattern Rules

A pattern rule looks like a regular rule, but uses ‘%’ as a wildcard in the target and one of their dependencies:

src/test/java/%.class: src/test/java/%.java junit4.jar javac -cp junit4.jar -g src/test/java/$*.java

Another implicit variable, $* contains the string matched by the % wildcard.

One advantage of pattern rules, is that we can add dependencies on other files e.g., junit.jar

3 Working with Make3.1 Touching FilesModification Dates

make compares the modification dates of targets and dependencies to determine if the target is out of date.

It uses the success/fail status value returned by commands to determine if construction of a target was successful.

Although this is fairly robust, there are ways to fool make

Touching a File

The touch command in *nix sets a files modification date to the current time, without affecting the contents of the file.

Page 390: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Question: What would happen if we touched code2html.flex?

Answer +

Page 391: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The next time that make is run, it will

1. run jflex to produce a new CppJavaScanner.java2. run javac to produce a new CppJavaScanner.class3. run jar to produce a new codeAnnotation.jar

but it will not recompile code2HTML.java

Sometimes this is a useful thing to do on purpose.

Inadvertant Touches

Suppose we had our code annotation project in a directory project1 and did the following:

> cd project1 > make > cd .. > cp -rf project1 project2 > cd project2 > make

What would be re-built by the second make?

Almost impossible to tell. All of the files in project2 would have create/modify dates within a second of each other. Ordering, if any, would be arbitrary.

(better to have done cp -arf project1 project2)

Inadvertant Touches

Similarly, successive calls to make can sometimes be confused if the time between creation of some intermediate targets is within a single clock “tick”.

Clock drift between different machines can be particularly troublesome.

(particular between the server running the make command and a file server responsible for storing the files).

Created != Success

Some commands we might give to create a target will create no file if the command fails.

e.g., g++ does not create a .o file if compilation errors occur

Page 392: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Others will create some kind of file anyway.

E.g., any command that is invoked with output redirection,

command > target

which could cause make to assume that the target need not be re-constructed the next time around.

Some make programs explcitly delete targets if the command fails.

3.2 Artificial TargetsFooling make Again

A creative way to fool make:

What happens if we give a rule whose commands never actually create the target?

target: dependency1 dependency2 echo Nope. Not going make that target!

The first time we run make, the dependencies will be created and the echo performed.

Each subsequent time we run make, the dependencies will be re-created if necessary and the echo performed.

Artificial Targets

We can take advantage of this trick by adding artificial targets that serve as the names for tasks to be performed.

build: codeAnnotation.jar install: build cp codeAnnotation.jar $(INSTALLDIR) clean: rm *.class CppJavaScanner.java codeAnnotation.jar: code2HTML.class CppJavaScanner.class jar tvf codeAnnotation.jar code2HTML.class CppJavaScanner.class CppJavaScanner.class: CppJavaScanner.java

Page 393: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

javac CppJavaScanner.java code2HTML.class: code2HTML.java CppJavaScanner.java javac code2HTML.java CppJavaScanner.java: code2html.flex java -cp JFlex.jar JFlex.Main code2html.flex

Common Artificial Targets

allOften made the first rule in the makefile so that it becomes the default. Builds everything. May also run tests.

buildBuild everything.

installBuild, then install

testBuild, then run tests

cleanDelete everything that would have been produced by the makefile in a build or test run.

3.3 Dependency AnalysisComing up with a list of dependencies (and keeping it current) can be troublesome.

Various tools exist for this purpose for programming languages

The gcc and g++ compilers have a compile-time option, -MMd, which emits a .d file containing a target and dependency line.

Use this with an implicit rule to give the actual command

Self-Building Makefile

selfBuilding.listing +

MAINPROG=testpicture CPPS:=$(wildcard *.cpp) CPPFLAGS=-g -D$(DISTR)CPP=g++

Page 394: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

OBJS=$(CPPS:%.cpp=%.o)DEPENDENCIES = $(CPPS:%.cpp=%.d) %.d: %.cpp touch $@ %.o: %.cpp $(CPP) $(CPPFLAGS) -MMD -o $@ -c $*.cpp make.dep: $(DEPENDENCIES) -cat $(DEPENDENCIES) > $@ include make.dep

On the first make,

for each .cpp file, an empty .d file is created by touchAll *.d files are concatenated to for a file make.depThe file make.dep is included as part of the makefile.As the .cpp files are compiled, the .d are replaced by a rule making the .o file dependent on that .cpp file and on any .h files that it included.

On subsequent make runs,

the .d files contain the dependencies for each .cpp file.All *.d files are concatenated to for a file make.depThe file make.dep is included as part of the makefile.If any .h or .cpp file has been changed, the .o files dependent on it will be regenerated.

3.4 Managing Subproject BuildsSubprojects are generally handled by giving each subproject its own makefile and using a master makefile to invoke the artificial targets:

all: cd model; make cd vcncurses; make cd vcjava; make clean: cd model; make clean cd vcncurses; make clean cd vcjava; make clean

Page 395: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4 Case Studies – IntroductionFor make and for the other buiild managers we will be discussing, we will use 3 case studies.

4.1 Simple Java BuildThe simple Java build features

Java code to be compiled and built into a jar.

JUnit tests to be compiled and run.

Layout

We will follow the Apache/Android guidelines for source code layout.

project root/ |--src/ |--|--main/ |--|--|--java/ |--|--|--|-- ...java packages... |--|--test/ |--|--|--java/ |--|--|--|-- ...junit packages... |--|--|--data/ |--|--|--|-- ...test data ... |--lib/ |--|-- ...3rd party libraries (temporary hack)...

We will look at better ways to supply 3rd party libraries in later lessons on configuration management.

Layout

For outputs from the build, we will follow either the Apache

project root/ |--target/ |--|--classes/ |--|--|-- ...compiled code from src/main |--|--test-classes/

Page 396: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

|--|--|-- ...compiled code from src/test |--|--reports/

or the Android standard

project root/ |--build/ |--|--classes/ |--|--|--main/ |--|--|--|-- ...compiled code from src/main |--|--|--test/ |--|--|--|-- ...compiled code from src/test |--|--lib/ |--|--reports/

whichever is more “natural” for the build manager under discussion.

4.2 Java Build with Code GenerationA slightly less conventional build:

Java code to be compiled and built into a jar.

Some of the Java code is generated automatically

JFlex program is used to produce lexical analyzers from collections of regular expressions.

JUnit tests to be compiled and run.

Layout

Project layout is the same as the simple Java build, except for an input directory for JFlex specifications and a working directory for the generated Java sourcecode:

project root/ |--src/ |--|--main/ |--|--|--java/ |--|--|--|-- ...java packages... |--|--|--jflex/ |--|--|--|-- ...JFlex input files... |--|--test/ |--|--|--java/

Page 397: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

|--|--|--|-- ...junit packages... |--|--|--data/ |--|--|--|-- ...test data ... |--lib/ |--|-- ...3rd party libraries (temporary hack)... |--target/ (or build/) |--|--generated-src/ |--|--|-- ...Java code generated by JFlex |--|...

4.3 C++ Multi-project BuildC and C++ pose a challenge for the build systems that want to provide defaults for simple projects.

A collection of .o files can only be linked together if they have no more than one main() function.

If you want a project to produce more than one executable, you have to tell the build manager how to divide up the .o files for each one.

Most IDE build managers and most default rules for non-IDE build managers don’t allow that.

One project – one executable

But unit testing adds additional executables.

Unit testing and C/C++ Builds

Even simple projects with unit tests wind up being divided into multiple sub-projects.

One or more sub-projects for groups of ADTs with unit tests.A subproject for each “real” executable.If not all developers will have the C/C++ unit test framework pre-installed, that may be another subproject.

4.3.1 Source Layout

project root/ |--lib/ (ADTs with unit tests) |--|--src/ |--|--|--main/ |--|--|--|--cpp/ |--|--|--|--|-- .cpp and local .h files for ADTs |--|--|--|--headers/ |--|--|--|--|-- Header files "exported" to other subprojects |--|--|--mainTest/

Page 398: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

|--|--|--|--cpp/ |--|--|--|--|-- .cpp unit tests (GTest) |--exe/ (may be named for executable, particularly if more than one) |--|--src/ |--|--|--main/ |--|--|--|--cpp/ |--|--|--|--|-- .cpp main function for one executable |--gtest/ (Google Test framework) |--|--include/ |--|--|-- Header files exported to unit tests |--|--|--src/ |--|--|--|-- .cpp and local .h files for framewwork

The gtest/ subproject has a slightly different layout because it’s a third party project and it’s not worth trying to repackage their sourcecode.

4.3.2 Output layout

The lib/ and gtest/ subprojects each produce a static library.The exe subproject produces an executable

project root/ |–lib/ (ADTs with unit tests) |–|–build/ |–|–|–objs/ holding area for .o files |–|–|–libs/ generated library goes here |–|–|–test-results/ reports fromunit test |–exe/ (may be named for executable, particularly if more than one) |–|–build/ |–|–|–objs/ holding area for .o files |–|–|–exe/ generated executablesgo here |–gtest/ (Google Test framework) |–|–build/ |–|–|–objs/ holding area for .o files |–|–|–libs/ generated library goes here

5 Case Studies – Makefiles5.1 Simple Java Build – Makefiles

TARGET=codeAnnotation.jar SRC=src/main/java ➀ CLASSDEST=build/classes JARDEST=build TESTSRC=src/test/java TESTCLASSDEST=build/testclasses JAVA=$(shell find $(SRC) -type f -name '*.java') ➁ TESTJAVA=$(shell find $(TESTSRC) -type f -name '*.java') CLASSES=$(patsubst $(SRC)/%, $(CLASSDEST)/%, $(JAVA:%.java=%.class)) TESTCLASSES=$(patsubst $(TESTSRC)/%, $(TESTCLASSDEST)/%, $(TESTJAVA:%.java=%.class)) TESTCLASSNAMES=$(subst /,.,$(subst $(TESTSRC)/, ,$(TESTJAVA:%.java=%)))

Page 399: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

.SUFFIXES: ## Targets:#all: test $(JARDEST)/$(TARGET) build/setup: ➂ -mkdir -p $(JARDEST) -mkdir -p $(CLASSDEST) -mkdir -p $(TESTCLASSDEST) date > $@ $(JARDEST)/$(TARGET): $(CLASSES) ➃ cd $(CLASSDEST); jar cf temp.jar * mv $(CLASSDEST)/temp.jar $@ test: $(TESTCLASSES) $(CLASSES) ➄ java -cp lib/junit-4.10.jar:lib/junit/hamcrest-core-1.1.jar:$(CLASSDEST):$(TESTCLASSDEST) org.junit.runner.JUnitCore $(TESTCLASS $(CLASSDEST)/%.class: $(SRC)/%.java build/setup ➅ javac -g -cp $(CLASSDEST) -d $(CLASSDEST) -sourcepath $(SRC) $(SRC)/$*.java $(TESTCLASSDEST)/%.class: $(TESTSRC)/%.java build/setup $(CLASSES) javac -g -cp $(CLASSDEST):lib/junit-4.10.jar:lib/junit/hamcrest-core-1.1.jar -d $(TESTCLASSDEST) -sourcepath $(TESTSRC) $(TESTS clean: -rm -f build

➀ Symbolic names for directories make it easier to rearrange layout.

➁ Various functions for manipulating and rewriting lists of files

➂ Create output directories. Note that this appears as a dependency in most of the later compilation rules (to guarantee it’s done before compiling).

➃ Build a Jar file

➄ Run the unit tests

Page 400: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

➅ Compile .cpp files.

5.2 Java Build with Code Generation – MakefileThis project adds a stage before compilation to generate some of the source code that then needs to be compiled.

TARGET=codeAnnotation.jar SRC=src/main/java CLASSDEST=build/classes JARDEST=build TESTSRC=src/test/java TESTCLASSDEST=build/testclasses GENSRC=build/gen/java GENDEST=build/classes FLEXSRC=src/main/jflex JAVA=$(shell find $(SRC) -type f -name '*.java') TESTJAVA=$(shell find $(TESTSRC) -type f -name '*.java') CLASSES=$(patsubst $(SRC)/%, $(CLASSDEST)/%, $(JAVA:%.java=%.class)) TESTCLASSES=$(patsubst $(TESTSRC)/%, $(TESTCLASSDEST)/%, $(TESTJAVA:%.java=%.class)) TESTCLASSNAMES=$(subst /,.,$(subst $(TESTSRC)/, ,$(TESTJAVA:%.java=%))) GENJAVA=$(GENSRC)/CppJavaScanner.java $(GENSRC)/CppJavaTeXScanner.java \ $(GENSRC)/ListingScanner.java $(GENSRC)/ListingTeXScanner.java GENCLASSES=$(GENDEST)/CppJavaScanner.class $(GENDEST)/CppJavaTeXScanner.class \ $(GENDEST)/ListingScanner.class $(GENDEST)/ListingTeXScanner.class .SUFFIXES: ## Targets:#all: test $(JARDEST)/$(TARGET) build/setup: -mkdir -p $(JARDEST) -mkdir -p $(GENSRC) -mkdir -p $(CLASSDEST) -mkdir -p $(TESTCLASSDEST) date > $@ $(JARDEST)/$(TARGET): $(CLASSES) cd $(CLASSDEST); jar cf temp.jar * mv $(CLASSDEST)/temp.jar $@

Page 401: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

test: $(TESTCLASSES) $(CLASSES) java -cp lib/junit-4.10.jar:lib/junit/hamcrest-core-1.1.jar:$(CLASSDEST):$(TESTCLASSDEST) org.junit.runner.JUnitCore $(TESTCLASS $(GENSRC)/CppJavaScanner.java: $(FLEXSRC)/code2html.flex build/setup java -jar lib/jflex-1.4.3.jar -d $(GENSRC) $< $(GENSRC)/CppJavaTeXScanner.java: $(FLEXSRC)/code2tex.flex build/setup java -jar lib/jflex-1.4.3.jar -d $(GENSRC) $< $(GENSRC)/ListingScanner.java: $(FLEXSRC)/list2html.flex build/setup java -jar lib/jflex-1.4.3.jar -d $(GENSRC) $< $(GENSRC)/ListingTeXScanner.java: $(FLEXSRC)/list2tex.flex build/setup java -jar lib/jflex-1.4.3.jar -d $(GENSRC) $< $(GENDEST)/%.class: $(GENSRC)/%.java build/setup javac -g -d $(GENDEST) -sourcepath $(GENSRC) $(GENSRC)/$*.java $(CLASSDEST)/%.class: $(SRC)/%.java build/setup $(GENCLASSES) javac -g -cp $(CLASSDEST) -d $(CLASSDEST) -sourcepath $(SRC) $(SRC)/$*.java $(TESTCLASSDEST)/%.class: $(TESTSRC)/%.java build/setup javac -g -cp $(CLASSDEST):lib/junit-4.10.jar:lib/junit/hamcrest-core-1.1.jar -d $(TESTCLASSDEST) -sourcepath $(TESTSRC) $(TESTS clean: -rm -f build

5.3 C++ Multi-project Build – MakefilesBecause this project is divided into multiple subprojects, we will have multiple makefiles:

One per subprojectAnd a master to launch them all.

5.3.1 The master file

Page 402: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

In the project root directory:

all: $(MAKE) -C gtest $(MAKE) -C lib $(MAKE) -C exe clean: $(MAKE) -C gtest $(MAKE) -C lib $(MAKE) -C exe

5.3.2 The lib subproject

TARGET=libmain.a ➀ CXX=g++ CXXFLAGS=-g -pthread -I ../gtest/include -I src/main/headers -std=c++11LINK=$(CXX) LFLAGS=../gtest/build/libs/libgtest.a -lpthread SRC=src/main/cpp OBJDEST=build/objs/main DEST=build/libs EXEDEST=build/exe TESTSRC=src/mainTest/cpp TESTOBJDEST=build/objs/test CPP=$(wildcard $(SRC)/*.cpp) OBJS=$(patsubst $(SRC)/%, $(OBJDEST)/%, $(CPP:%.cpp=%.o)) TESTCPP=$(wildcard $(TESTSRC)/*.cpp) TESTOBJS=$(patsubst $(TESTSRC)/%, $(TESTOBJDEST)/%, $(TESTCPP:%.cpp=%.o)) .SUFFIXES: ## Targets:#all: $(DEST)/$(TARGET) test build/setup: ➁ -mkdir -p $(DEST) -mkdir -p $(EXEDEST) -mkdir -p $(OBJDEST) -mkdir -p $(TESTOBJDEST)

Page 403: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

date > $@ test: $(EXEDEST)/runtest ➂ $(EXEDEST)/runtest $(DEST)/$(TARGET): $(OBJS) test build/setup ➃ ar rcs $@ $(OBJS) ranlib $@ $(EXEDEST)/runtest: $(TESTOBJS) $(OBJS) ➄ $(LINK) -o $@ $(CPPFLAGS) $(TESTOBJS) $(OBJS) $(LFLAGS) $(OBJDEST)/%.o: $(SRC)/%.cpp build/setup ➅ $(CXX) $(CXXFLAGS) -o $@ -c $< $(TESTOBJDEST)/%.o: $(TESTSRC)/%.cpp build/setup ➆ $(CXX) $(CXXFLAGS) -o $@ -c $< clean: -rm -f build

➀ Symbolic names for directories, programs, and lists of files.

➁ Set up output directories

➂ Run the unit tests.

➃ Create the library from the .o files generated by compilation

➄ Generate the executable for running unit tests.

➅ Compile the ADTs source code

➆ Comile the unit test source code.

Page 404: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Task Dependencies: antSteven J Zeil

Last modified: Mar 25, 2020

Contents:1 The ant Command2 Build Files

2.1 Targets2.2 Ant Building Blocks and Concepts2.3 Tasks

3 Case Studies3.1 Simple Java Build3.2 Java Build with Code Generation3.3 C++ Multi-project Build

4 Eclipse/Ant Integration

Abstract

ant is a build manager based upon a task dependency graph expressed in an XML file

In this lesson we look at how ant addresses a number of shortcomings of make.

We will look at the task-based build model implemented by ant at how this differs from the dependency-based model of make, and at how to describe projectsto the ant tool.

We will look at how ant could be applied to some of our sample projects.

ant

ant devised by James Davidson of Sun, contributed to Apache project (along with what would eventually become TomCat), released in 2000

Quickly became a standard tool for Java projects

slower to move into other arenas

Page 405: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What’s Wrong with make?

ant is actually an acronym for Another Neat Tool.

But why do we need “another” tool, however neat, for build management?

make works by issuing commands to /bin/sh

That’s not portable.

The commands that people write into their makefile rules are generally not portable either:

Commands themselves are system-dependent (e.g., mkdir, cp, chmodPaths are system-dependent (/ in *nix versus \ in Windows, legal characters, quoting rules)Path lists are system-dependent (: in *nix versus ; in Windows)

Other Criticisms

Some feel that make is too low-level with its focus on individual files

Some will feel that ant is too high-level

But this is the apparent rationale for moving the focus from file dependencies to task dependencies.

The makefile syntax is arcane and hard to work with.

And XML syntax isn’t?

1 The ant Command

ant looks for its instructions in a file named, by default, build.xml

The ant command can name any target to be built, e.g.,

ant setup

If no target is given, ant builds a target explicitly listed in build.xml as a default for the project.

Page 406: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

ant Options

Some useful options:

-k, -keep-going“Keep going.” Don’t stop the build at the first failue, but continue building any required targets that do not depend on the one whose construction hasfailed.

-f filenameUse filename instead of the default build.xml. Also -file or -buildfile

-Dproperty=valueSets a property (similar to make’s variables)

2 Build FilesThe ant build file is an XML file.

The build file describes a project.

Page 407: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The project has a name and a default target.

<project name="382Website" default="deploy"> <description> Extract Metadata Extractor - top level </description> ⋮ </project>

2.1 TargetsAt its heart, a build file is a collection of targets.

A target is an XML element and, as attributes, has a name and, optionally,

a list of dependenciesa conditiona human-readable description

The target can contain multiple tasks, which contain the actual “commands” to get things done.

ant targets correspond, roughly, to make’s “artificial targets”.

Example of Targets

simplebuild.xml.listing +

<project name="JavaBuild" default="deploy"> ➀ <description> Example of a simple project build </description> <target name="compile" description="Compile src/.../*.java into bin/"> ➁ <mkdir dir="bin" /> ➂ <javac srcdir="src" destdir="bin" debug="true" includeantruntime="false"/> <echo>compiled </echo> </target> <target name="unittest" depends="compile" unless="test.skip"> ➃ <mkdir dir="test-reports" /> <junit printsummary="on" haltonfailure="true" fork="true" forkmode="perTest">

Page 408: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<formatter type="plain" /> <batchtest todir="test-reports"> <fileset dir="bin"> <include name="**/Test*.class" /> <exclude name="**/Test*$*.class" /> </fileset> </batchtest> </junit> </target> <target name="deploy" depends="unittest" description="Create project's Jar file"> <jar destfile="myProject.jar"> <fileset dir="bin"/> </jar> </target></project>

➀ The project has a name and default target

➁ A basic target. It is named “compile” and has a description (which may be picked up by some IDEs)

➂ This target has 3 tasks. It creates a directory, compiles Java source code, and prints a message when completed.

The fact that the tag names resemble familiar commands is intended as self-documentation, but is not otherwise significant.The tag names actually map to Java class names that implement the task.

➃ This target illustrates both a dependency and a condition.

The tasks within this target would not be executed if I invoked ant like this:

ant -Dtest.skip=1

However, the unittest task would still be considered to have succeeded, in the sense that tasks that depend on it would be allowed to run.

Task versus File Dependencies

ant targets correspond, roughly, to make’s “artificial targets”.

So this build file

simplebuild.xml.listing +

<project name="JavaBuild" default="deploy"> ➀ <description>

Page 409: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Example of a simple project build </description> <target name="compile" description="Compile src/.../*.java into bin/"> ➁ <mkdir dir="bin" /> ➂ <javac srcdir="src" destdir="bin" debug="true" includeantruntime="false"/> <echo>compiled </echo> </target> <target name="unittest" depends="compile" unless="test.skip"> ➃ <mkdir dir="test-reports" /> <junit printsummary="on" haltonfailure="true" fork="true" forkmode="perTest"> <formatter type="plain" /> <batchtest todir="test-reports"> <fileset dir="bin"> <include name="**/Test*.class" /> <exclude name="**/Test*$*.class" /> </fileset> </batchtest> </junit> </target> <target name="deploy" depends="unittest" description="Create project's Jar file"> <jar destfile="myProject.jar"> <fileset dir="bin"/> </jar> </target></project>

is roughly equivalent to this makefile

simplemake.listing +

JAVAFILESsrc=$(shell find src/ -name '*.java') JAVAFILES=$(JAVAFILESsrc:src/%=%) CLASSFILES=$(JAVAFILES:%.java=%.class) TESTFILES=$(shell find src/ -name 'Test*.java') TESTS=$(TESTFILES:src/%.java=%) deploy: unittest cd bin; jar cvf myProject.jar `find . -name '*.class'` unittest: build cd bin; for test in $(TESTS); do \ java $$test; \ done

Page 410: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

build: cd src; javac -d ../bin -g $(JAVAFILES)

though a “real” makefile author would probably write this:

simplemake2.listing +

JAVAFILESsrc=$(shell find src/ -name '*.java') JAVAFILES=$(JAVAFILESsrc:src/%=%) CLASSFILES=$(JAVAFILES:%.java=%.class) TESTFILES=$(shell find src/ -name 'Test*.java') TESTS=$(TESTFILES:src/%.java=%) deploy: myProject.jar unittest: testReport.txt build: $(CLASSFILES) myProject.jar: testReport.txt $(CLASSFILES) cd bin; jar cvf myProject.jar `find . -name '*.class'` testReport.txt: $(CLASSFILES) -rm testReport.txt cd bin; for test in $(TESTS); do \ java $$test >> testReport.txt; \ done bin/%.class: src/%.java cd src; javac -d ../bin -g $*.java

Make Efficiency

If we do

make make

The second command does not actually perform any steps.

Ant Efficiency

What happens if we do

Page 411: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

ant ant -Dskip.test=1

Each of the tasks is executed, but

The javac task knows not to re-compile Java files with up-to-date class files

The jar task knows not to update Jar files that are newer than all of the files being added.

If we remove the -Dskip.test=1, however, the tests will be re-run.

So some level of incremental behavior gets built into many of the individual tasks.

The idea of avoiding unnecessary work is a fundamental part of make.But it’s not fundamental to ant. It depends on the implementation of each individual task.

2.2 Ant Building Blocks and Concepts(Optional reading. Read on if you actually want to use Ant.)

2.2.1 Properties

Properties are named string values.

Can be set from the command line or via <property and a few other tasks

Accessed as ${_propertyName_}

Properties are immutable: once set, attempts to re-assign their values are ignored

By convention, properties names are grouped into faux hierarchies with ‘.’

e.g., compile.src, compile.dest, compile.options

The <property Task

Two basic modes:

<property name="compile.options" value="-g -O1"/>

Sets this property to “-g -O1”

Page 412: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<property name="compile.src" location="src/main/java"/>

Sets this property to the absolute path of the directory/file named.

The / and \ characters are changed as necessary to conform to the OS on which ant is being run.

Additional <property Variants

<property file="project.default.properties"/>

Loads property values from a file, written as a series of property=_value_ lines

courseName=CS795baseurl=https://www.cs.odu.edu/~zeil/cs795SD/s13homeurl=https://www.cs.odu.edu/~zeil/cs795SD/s13/Directory/[email protected]

A common use of this it to load in a personal file of login credentials and other private data:

<property file="${user.home}/.ant-global.properties"/>

The property ${user.home} maps to the user’s home directory as appropriate to the operating system. If the file .ant-global.properties exists,can load private info.

Should be protected (e.g., Unix protection 600)

If the file does not exist, this does nothing at all.

<property environment="env"/>

Copies the OS environment variables into the build state, prefaced by the indicated prefix

e.g., ${env.PATH}

2.2.2 File Sets and Lists

A file set is a collection of existing files

can be specified using wild cards

A file list is a collection of files that may or may not exist

Must be specified explicitly without wild cards

Page 413: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

File Sets

<fileset file="src/main.cpp"/><fileset dir="src" includes="main.cpp utility.h utility.cpp"/><fileset dir="src" includes="*.cpp,*.h"/>

More commonly seen as a nested form

<fileset id="unitTests" dir="bin"> <include name="**/Test*.class"/> <exclude name="**/*$*.class"/> <exclude name="**/*Debug.class"/></fileset>

The id in the prior example allows later references:

<fileset refid="unitTests"/>

File Lists

<filelist dir="src" files="main.cpp utilities.h utilities.cpp"/>

Can also use id or refid attributes

Mappers

Allow for a transformation of file names

Some commands use a file set to describe inputs, then a mapper to describe outputs

<fileset dir="src" includes="*.cpp"/><globmapper from="*.cpp" to="*.o"/>

would map each file in src/*.cpp to a corresponding .o file

And

Page 414: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<fileset dir="bin" includes="**/Test*.java"/><packagemapper from="*.class" to="*"/>

would map a compiled unit test file project/package/TestADT.class to project.package.TestADT

There are several other mappers as well

Selectors

Selectors provide more options for selecting files than simple include/exclude based on the names.

For example, our previous examples assumed that unit tests would be identified by file name Test*.java.

Here we look instead for any Java file containing the JUnit4 @Test annotation.:

<fileset id="unitTestSrc" dir="src"> <include name="**/Test*.java"/> <contains text="@Test" casesensitive="no"/></fileset>

Other selectors replicate several of the tests from the classic Unix find command

2.2.3 Path Sets

Used to specify a sequence of paths, usually to be searched.

<classpath> <pathelement path="${env.CLASSPATH}"/> <fileset dir="target/classes"> <include name="**/*.class"/> </fileset> <filelist refid="third-party_jars"/></classpath>

Referencing Path Sets

For reason unclear to me, you cannot name classpaths and re-use them directly, but must do it this way

<path name="test.compile.classpath"> <pathelement path="${env.CLASSPATH}"/> <fileset dir="target/classes">

Page 415: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<include name="**/*.class"/> </fileset> <filelist refid="third-party_jars"/></path> ⋮ <classpath refid="test.compile.classpath"/>

2.2.4 Filters

Filters are used to modify the outputs of some commands by performing various substitutions:

<copy file="../../templates/@{format}.tex" tofile="${doc}-@{format}.ltx"> <filterset> <filter token="doc" value="${doc}"/> <filter token="relPath" value="${relPath}"/> <filter token="format" value="@{format}"/> </filterset></copy>

A filter set replaces tokens like @doc@ by a string, in this case the value of the property ${doc}

Filter Chains

Filter chains offer a variety of more powerful options, e.g.,

<loadfile property="doctitle" srcfile="${doc}.info.tex"> <filterchain> <linecontains> <contains value="\title{"/> </linecontains> <tokenfilter> <replaceregex pattern=" *\\title[{]([^}]*)[}]" replace="\1"/> </tokenfilter> </filterchain></loadfile>

loadfile loads an entire file into a property

The linecontains filter limits the portion of the file loaded to any line containing a LaTeX \title{…} command.

The tokenfilter filter does a regular expression match and replace on that line to extract only the portion of that line between the { ... }.

Page 416: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.3 TasksThe Ant Manual has a good breakdown on these.

Consistent with their XML structure, tasks can be parameterized via attributes or nested XML attributes

Sometimes you can do the same thing either way.

Look at:

File tasks: copy, delete, mkdir, move, fixcrlf, syncCompile tasks: javac, dependArchive, documentation, testing tasksExecution tasks: java, exec, apply

Extending Ant

Ant has a built-in macro capability

More powerful extension is accomplished by adding Java classes, mapped onto task names:

<project name="code2html" default="build"> <taskdef classpath="JFlex.jar" classname="JFlex.anttask.JFlexTask" name="jflex" /> ⋮ <target name="generateSource"> <mkdir dir="src/main/java"/> <jflex file="src/main/jflex/code2html.flex" destdir="src/main/java"/> <jflex file="src/main/jflex/code2tex.flex" destdir="src/main/java"/> ⋮

Finding Extensions

Many Java-oriented tools (e.g. JFlex) come with an ant task as part of the package.

Other are contributed by users of the tool, (e.g. LaTeX)

Page 417: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Some general-purpose Ant libraries.

e.g., antcontrib adds

C/C++ compilationIf and For-loopoutofdate (a make-like file dependency wrapper)enhanced property tasks (e.g., URL encoding)

3 Case Studies3.1 Simple Java Build

build.xml.sjb.listing +

<project name="codeAnnotation" basedir="." default="build" xmlns:ivy="antlib:org.apache.ivy.ant"> <record name="ant.log" action="start" append="false" /> ➀ <path id="testCompilationPath"> ➁ <fileset dir="lib" includes="*.jar"/> <pathelement path="target/classes"/> </path> <path id="testExecutionPath"> <fileset dir="lib" includes="*.jar"/> <pathelement path="target/classes"/> <pathelement path="target/test-classes"/> </path> <property name="build.dir" value="build"/> <property name="src.dir" value="src"/> <import file="ivyBuild.xml" as="ivy"/> ➂ <target name="compile" depends="ivy.resolve-ivy" ➃ description= "Compile all source code, including the lexical analysis code generated using jflex." > <mkdir dir="target/classes"/>

Page 418: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<javac srcdir="src/main/java" destdir="target/classes" source="1.8" includeantruntime="false"/> </target> <target name="compile-tests" depends="compile" ➄ description="Compile JUnit tests" > <mkdir dir="target/test-classes"/> <javac srcdir="src/test/java" destdir="target/test-classes" source="1.8" includeantruntime="false"> <classpath refid="testCompilationPath"/> </javac> </target> <target name="test" depends="compile-tests" description="Run all JUnit tests, producing a summary report in target/test-results." > <mkdir dir="target/test-results/details"/> <junit printsummary="yes" ➅ haltonfailure="no" fork="no" > <classpath refid="testExecutionPath"/> <formatter type="xml"/> <batchtest todir="target/test-results/details"> <fileset dir="target/test-classes"> <include name="**/*Test*.class"/> </fileset> </batchtest> </junit> <junitreport todir="target/test-results"> ➆ <fileset dir="target/test-results/details"> <include name="TEST-*.xml"/> </fileset> <report format="frames" styledir="junit-stylesheets" todir="target/test-results/html"/> </junitreport> </target> <target name="build" depends="test" description="Construct a jar file with the compiled code and a zip file with the project source code."> <jar destfile="codeAnnotation.jar" basedir="target/classes"> ➇ <manifest> <attribute name="Main-Class" value="edu.odu.cs.code2html.Code2HTML"/> </manifest> </jar>

Page 419: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

</target> <target name="clean"> ➈ <delete dir="target"/> </target> </project>

➀ Copy all messages to a log file, ant.log

➁ Set up some useful names for lists of paths.

➂ Ignore all “ivy” stuff for now. We’ll cover this in an upcoming lesson.

(OK, if you must know, this retrieves the latest versions of the JUnit and JFlex libraries from the internet and makes them available to this project build.)

➃ Compiles Java source code from src/main/java/, putting the .class files into target/classes/.

➄ Compiles Java source code from src/test/java/, putting the .class files into target/testclasses/.

I compile the tests separately from the “real” code so that later we can easily omit the test drivers from the published library’s binary code.

➅ Now we run the JUnit tests

haltonfailure stops the build if we failed tests, so we never move on and produce a jar with known buggy code.

➆ This produces an HTML report with summaries of how well our tests did. Example

➇ The compiled binaries for the “real” code (not the tests) are packaged into a .jar file.

Note that the .jar production is simplified by having separated the project and test compilation results.

➈ Clean up is simple: delete the target directory

You can find this entire project, with the Ant files, here.

3.2 Java Build with Code GenerationNot All Sourcecode is Hand-Written

This project adds a stage before compilation to generate some of the source code that then needs to be compiled.

Page 420: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

build.xml.jcg.listing +

<project name="codeAnnotation" basedir="." default="build" xmlns:ivy="antlib:org.apache.ivy.ant"> <record name="ant.log" action="start" append="false" /> <path id="testCompilationPath"> <fileset dir="lib" includes="*.jar"/> <pathelement path="target/classes"/> </path> <path id="testExecutionPath"> <fileset dir="lib" includes="*.jar"/> <pathelement path="target/classes"/> <pathelement path="target/test-classes"/> </path> <property name="build.dir" value="build"/> <property name="src.dir" value="src"/> <import file="ivyBuild.xml" as="ivy"/> <target name="generateSource" depends="ivy.resolve-ivy" description="Use jflex to process lexeme descriptions for C++ and Java, generating the Java source code for the resulting lexical analyzers." > <taskdef classpath="lib/jflex-1.4.3.jar" ➀ classname="JFlex.anttask.JFlexTask" name="jflex" /> <mkdir dir="target/gen/java"/> <jflex file="src/main/jflex/code2html.flex" ➁ destdir="target/gen/java"/> <jflex file="src/main/jflex/code2tex.flex" destdir="target/gen/java"/> <jflex file="src/main/jflex/list2html.flex" destdir="target/gen/java"/> <jflex file="src/main/jflex/list2tex.flex" destdir="target/gen/java"/> </target> <target name="compile" depends="generateSource" ➂ description= "Compile all source code, including the lexical analysis code generated using jflex." >

Page 421: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<mkdir dir="target/classes"/> <javac srcdir="target/gen/java" destdir="target/classes" ➃ source="1.7" includeantruntime="false"/> <javac srcdir="src/main/java" destdir="target/classes" source="1.7" includeantruntime="false"/> </target> <target name="compile-tests" depends="compile" description="Compile JUnit tests" > <mkdir dir="target/test-classes"/> <javac srcdir="src/test/java" destdir="target/test-classes" source="1.7" includeantruntime="false"> <classpath refid="testCompilationPath"/> </javac> </target> <target name="test" depends="compile-tests" description="Run all JUnit tests, producing a summary report in target/test-results." > <mkdir dir="target/test-results/details"/> <junit printsummary="yes" haltonfailure="no" fork="no" > <classpath refid="testExecutionPath"/> <formatter type="xml"/> <batchtest todir="target/test-results/details"> <fileset dir="target/test-classes"> <include name="**/*Test*.class"/> </fileset> </batchtest> </junit> <junitreport todir="target/test-results"> <fileset dir="target/test-results/details"> <include name="TEST-*.xml"/> </fileset> <report format="frames" styledir="junit-stylesheets" todir="target/test-results/html"/> </junitreport> </target> <target name="build" depends="test" description="Construct a jar file with the compiled code and a zip file with the project source code."> <jar destfile="codeAnnotation.jar" basedir="target/classes"> <manifest> <attribute name="Main-Class" value="edu.odu.cs.code2html.Code2HTML"/>

Page 422: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

</manifest> </jar> </target> <target name="clean"> <delete dir="target"/> </target> <target name="cleaner" depends="clean"> <delete dir="lib"/> </target> <target name="cleanest" depends="cleaner"> <delete dir="ivy"/> </target> </project>

➀ The taskdef “declares” a new jflex task.

➁ Here we use jflex to generate a scanner from several sets of regular expressions.

The source code for the new scanner is placed in target/gen/java, keeping it separate from our hand-written code.

➂ Compilation can only occur if generateSource was run.

➃ Here I have modified my original compilation instructions to also compile any Java source code in the new src/generated/java directory.

You can find this entire project, with the Ant files, here.

3.3 C++ Multi-project BuildBecause this project is divided into multiple subprojects, we will have multiple build.xml files:

One per subprojectAnd a master to launch them all.

3.3.1 The master file

In the project root directory:

build.xml.manroot.listing +

Page 423: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<project name="manhattan" basedir='.' default="build"> <record name="ant.log" action="start" append="false" /> <!-- Invoke this build file as ant - to build the project ant clean - to clean out all generated files --> <target name="build"> <ant target="build" antfile="gtest/build.xml" inheritAll="false"/> <ant target="build" antfile="lib/build.xml" inheritAll="false"/> <ant target="build" antfile="exe/build.xml" inheritAll="false"/> </target> <target name="clean"> <ant target="clean" antfile="gtest/build.xml" inheritAll="false"/> <ant target="clean" antfile="lib/build.xml" inheritAll="false"/> <ant target="clean" antfile="exe/build.xml" inheritAll="false"/> </target> </project>

3.3.2 The lib subproject

build.xml.manlib.listing +

<project name="manhattan-lib" basedir="." default="build" xmlns:cpptasks="antlib:net.sf.antcontrib.cpptasks" > <description> Builds the ADTs for the manhattan program. </description> <property file="${user.home}/.ant-global.properties"/> <record name="ant.log" action="start" append="false" /> <taskdef classpath="../antcontrib-cpptasks.jar" ➀ resource="net/sf/antcontrib/cpptasks/antlib.xml" /> <target name="compile"> <mkdir dir="build/objs/main"/>

Page 424: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<mkdir dir="build/libs"/> <cc outtype="static" ➁ subsystem="console" name="g++" outfile="build/libs/main" objdir="build/objs/main"> <fileset dir="src/main/cpp"> <include name="**/*.cpp"/> </fileset> <includepath path="src/main/headers"/> </cc> </target> <target name="compiletest" depends="compile"> ➂ <mkdir dir="build/objs/test"/> <mkdir dir="build/exe"/> <cc outtype="executable" subsystem="console" name="g++" objdir="build/objs/test"> <fileset dir="src/mainTest/cpp"> <include name="**/*.cpp"/> </fileset> <compilerarg value='-g'/> <compilerarg value='-pthread'/> <includepath path="src/main/headers"/> <includepath path="../gtest/include"/> </cc> <apply executable="g++"> <!-- Using apply because I can't get ➃ linking to work in antcontrib --> <arg value="-o"/> <arg value="build/exe/runTests"/> <arg value="../gtest/build/libs/libgtest.a"/> <arg value="build/libs/libmain.a"/> <arg value="-lpthread"/> <fileset dir="build/objs/test"> <include name="*.o"/> </fileset> </apply> </target> <target name="test" depends="compiletest"> <exec executable="build/exe/runTests"/> ➄ </target> <target name="build" depends="test"/> <target name="clean"> <delete dir="build"/>

Page 425: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

</target> </project>

➀ AntContrib provides a set of C++ tasks.

➁ Compile the source code. The outtype indicates that we are generating a (static) library.

➂ Compile the unit tests. The outtype indicates that we are generating an executable.

➃ Unfortunately, I cannot get linking to work properly with the cc task, so I forced that as an OS command.

➄ Run the unit test executable.

The other subproject build.xml files are similar, but simpler.

You can find this entire project, with the Ant files, here.

4 Eclipse/Ant IntegrationLimitations of Eclipse Builder

Cannot run code-proprocessing (e.g., JFlex)

An Eclipse project is oriented towards producing a single output product (program, library, … )

With C++ projects, a problem if you have a “real” product

(e.g., a library) and a set of test drivers, each of which yields a distinct program executable.

Java projects have fewer problems (because executables don’t need separate processing),but what if you are planning to generate both

a binary distribution jar, anda source distribution jar?

Project Dependencies

Eclipse supports the idea of projects that depend on other projects, so you could do

project1 produces the binary distribution jar

Page 426: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

project2 depends on project1 and produces a source distribution jar

These projects must reside together in a known relative path from one anotherproject2 is not automatically rebuild if project1 has changed

Does not scale well.

For C++ are you going to have a distinct project for each test driver?

Eclipse/Ant Integration

Eclipse is generally ant-friendly.

Drop a build.xml file into a project and Eclipse will recognize it.

Right-clicking on it will bring up options to run it, or to configure how to run itincluding the selection of the targetsome preference given to targets with descriptions

Once ant has been run, the “Run Last Tool” button defaults to re-running it.

But the default build is still Eclipse’s default build manager

For projects with elaborate classpaths, requires keeping both the Eclipse project description and the build file up-to-date and consistent.Pre-compilation steps (e.g., tools that generate source code) are not re-run automatically when needed.

Eclipse Builders

Eclipse supports multiple, plug-able builders.

Open Project Properties and go to “Builders”

In a typical java project, you have just the “Java Builder”Click new to see options.

In this case, select “Ant Builder”.

Fill in the main screen. Leave “Arguments” blank.

Go to the Targets tab. Select appropriate targets for

Clean: Menu selection Project->clean

Page 427: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Manual build: What you want done after explicitly requesting a build

Auto build: What you want done after a file has been saved/changed

Return to the Builders list and uncheck the “Java Builder”

Page 428: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Managing Builds with MavenSteven J Zeil

Last modified: Mar 2, 2020

Contents:1 Why Maven?2 Maven as a Build Manager3 Case Studies

3.1 Simple Java Build3.2 Java Build with Code Generation3.3 C++ Multi-project Build

Abstract

Maven combines build management with configuration management (a future topic in this course). It attempts to standardize the build process in a way thatimproves consistency from project to project and enforces local best practices.

In this lesson, we will look at the capabilities and limitations of Maven and how projects can be structured to use it. We will look at how it works with some ofour sample projects.

1 Why Maven?Another Apache project, Maven came well after Ant had come to dominate the Java open source landscape.

Initially seen as a competitor or replacement for Ant

Maven addresses both

build management (as does Ant)and configuration management (which Ant does not)

Later, we’ll talk about Ivy, which adds configuration mgmt to Ant

Maven as a Build Manager

Maven uses an underlying task dependency model, but the tasks and their dependencies are pre-defined for a collection of archetype projects.

Page 429: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

As a consequence, maven offers far less flexibility than ant, but a basic, unaltered maven build may include tasks that less experienced developers would neverthink to include or might have difficulty adding to a more conventional build manager.

Motivations for Maven

Grew out of an observation that many supposedly cooperative, related Apache projects had inconsistent and incompatible ant build structures.

Stated goals are

Making the build process easy

Providing a uniform build system

Providing quality project information

Providing guidelines for best practices development

Allowing transparent migration to new features

Uniform Build System

Maven supports archetype projects that standardize

directory structure

Source code kept in separate directory tree from both intermediate and final build productsTests occupy separate subtrees of the source and product trees

“Life Cycle”

Really, a presumptuous name on their part for a build processA sequence of goals

Archetypes can be obtained from the Maven project or tailored for an organization.

Providing quality project information

Provides easy access to report tools

Aids in building & maintaining project web sites (e.g.)

Page 430: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Providing guidelines for best practices development

Directory structures (already discussed)

Unit testing

Encourage familiarity with approved archetypes

2 Maven as a Build ManagerPerhaps the best way to illustrate this is to follow the steps in Maven in 5 Minutes

Start with the command

mvn archetype:generate -DgroupId=edu.odu.cs \ -DartifactId=codeAnnotation \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false

Lots of libraries (mainly comprising the latest version of Maven system itself) will be downloaded into your \string~/.m2 directory.A directory, codeAnnotation, will be created.

cd into the new directory and explore

src directory structurepom.xml is the build file for this project

Building with the Sample Source

Run

mvn package

Sample source code is compiledSample unit test is run and executed.A jar file is created with the sample source code

Explore the target directory to see what has been placed there

OK, that was fun…

Page 431: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Let’s try this with some real source code.

Delete the target directory (or run mvn clean)

Replace the contents of src/main/java and src/test/java by the corresponding contents from my code Annotation project.

Also, copy src/main/jflex while we’re at it, though we won’t use this right away.

Try mvn package again.

What Went Wrong?

A glance at the code with the error messages won’t show anything obvious.

But I happen to know that Maven defaults to running the Java compiler in Java 5 compatibility modeThis code uses Java 7 features

Edit the pom.xml file and, just above the <dependencies> section, add

<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties>

Then try mvn package again

That was a little better

The main source code compiled successfully.

The error was in the compilation of the unit tests

The first error message says

[ERROR] /home/.../codeAnnotation/src/test/java/edu/odu/cs/codeAnnotation/TestC2HOptions.java:[3,23] package org.junit does

Looks to be a problem with the JUnit library

In the original project, I was keeping a copy of junit4.jar in the project directory.

A clumsy solution

Page 432: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Which we’ll solve when we take up configuration management.

3 Case Studies3.1 Simple Java BuildWell, we pretty much just did that.

1. Use mvn archetype:generate to set up the directories and build file.

2. Replace maven’s “Hello World” code by the real source code.

3.2 Java Build with Code GenerationNot All Sourcecode is Hand-Written

This project adds a stage before compilation to generate some of the source code that then needs to be compiled.

pom.xml.listing +

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>edu.odu.cs</groupId> <artifactId>codeAnnotation</artifactId> <packaging>jar</packaging> <version>1.0</version> <name>codeAnnotation</name> <url>https://www.cs.odu.edu/~zeil/cs795SD/s13/Directory/topics.html</url> <description> This is a tool used to parse code listings and to generate syntax-highlighted C++/Java listings in both HTML and LaTeX. Markup can be added in the form of special comments that will be recognized as instructions to highlight blocks of code, to add callout symbols, or to insert vertical ellipses. </description> <!-- site generation: mvn test mvn surefire-report:report mvn site

Page 433: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

--> <repositories> </repositories> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>de.jflex</groupId> <artifactId>jflex</artifactId> <version>1.4.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>de.jflex</groupId> <artifactId>maven-jflex-plugin</artifactId> ➀ <version>1.4.3</version> <executions> <execution> <goals> <goal>generate</goal> ➁ </goals> </execution> </executions> </plugin> </plugins> </pluginManagement> </build> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties></project>

The highlighted portions represent (most) of the changes required.

➀ Here we announce our intention to use a plugin that adds a jflex step to a java build.

➁ Here we declare that jflex will be invoked during the generate build step.

Page 434: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

How do we know where to put our jflex input files?

We learn that by reading the documentation of the plugin.

How do we know that the proper time to use it is during the generate task?

We learn that by reading the documentation of the Java project archetype.

3.3 C++ Multi-project BuildNot even going to try and go there.

I’ve never had much luck getting maven to work with C++.

Page 435: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Task Dependencies: GradleSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Gradle Overview

1.1 What to keep and leave from Ant1.2 What to keep and leave from Maven1.3 What does Gradle offer?1.4 The Gradle Wrapper

2 Running Gradle3 Build Files

3.1 Gradle Tasks3.2 Anatomy of a Task3.3 Task Dependencies3.4 Tasks3.5 Doing Maven-Like Things with Gradle

4 Case Studies4.1 Simple Java Build4.2 Java Build with Code Generation4.3 C++ Multi-project Build

Abstract

Gradle is a build manager based upon an Ant-like task dependency graph expressed in a more human-friendly notation, with a Maven-like ability to expressstandard project layouts and build conventions.

In this lesson we look at how Gradle combines some of the better features of Ant and Maven, while providing a more convenient notation than either.

We will look at how Gradle could be applied to some of our sample projects.

1 Gradle OverviewGradle devised by GradleWare, founded by Hans Dockter, released in 2012

Page 436: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Has become the standard build tool for Android

Tries to strike a middle ground between Ant and Maven

1.1 What to keep and leave from AntKeep:

PortabilityBuild commands are described in a platform-independent manner.

FlexibilityAlmost any sequence of processing steps can be described.Allows for unconventional build sequencesAllows for unconventional build targets

Leave

XML as a build language.

“XML was an easy choice for a build tool a decade ago, when it was a new technology, developers were enthusiastic about it, and no one yet knewthe pain of reading it in large quantities. It seemed to be human-readable, and it was very easy to write code to parse it. However, a decade ofexperience has shown that large and complex XML files are only easy for machines to read, not for humans. Also, XML’s strictly hierarchicalstructure limits the expressiveness of the format. It’s easy to show nesting relationships in XML, but it’s hard to express program flow and dataaccess the way most common programming language idioms express them. Ultimately, XML is the wrong format for a build file.”

Tim Berglund, Learning and Testing with Gradle

Inability to express simple control flowe.g., loop through all files in a directory and do task

1.2 What to keep and leave from MavenKeep:

Dependency management

Gradle will work with Maven & Ivy repositories.Early versions of Gradle actually used Ivy, though eventually it gained its own dependency manager.

Page 437: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Standard directory layouts and build conventions for common project types.

If your project has nothing unusual about its build, you can sit back and use the defaults.

Leave

XML as a build language.

Inflexibility

If your project has anything unusual about its build, changing the defaults in Maven is frustrating.

Inability to express simple control flow

1.3 What does Gradle offer?Build files are written in Groovy

Groovy is a scripting language that runs in a Java JVMSyntax is Java-basedInterfacing with Java code is easy

Gradle adds build-specific functions as a Groovy library

Gradle is built on top of the Ant libraries.

All conventional Ant tasks are available.Ant build files can be incorporated as functions of a Gradle build.

Hans Dockter describes Gradle, compares it to Ant and Maven, and shows lots of examples (in Eclipse).

1.4 The Gradle WrapperSuppose that you are building your project with Gradle.

Other people may try to check out a copy of your code, including your Gradle build file.But maybe they won’t have Gradle on their machine.

If you set up your project with the Gradle Wrapper, you get a simple script named gradlew.

You invoke your build via ‘gradlew’ instead of ‘gradle’gradlew checks to see if the system on which it is running has Gradle installed.

Page 438: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

If not, it downloads a copy and installs it under $USER_HOME/.gradleIt then invokes gradle (old installation or new), passing any parameters you supplied to the gradlew command.

This works nicely for projects that distribute their source code via any of the version control systems that we will be discussing later.

2 Running Gradle

gradle looks for its instructions in a file named, by default, build.gradle

The gradle command can name any task (or list of tasks) as targets to bebuilt, e.g.,

gradle setup compile

If no target is given, gradle can use a default task if one has beendeclared in the build file.

gradle Options

Some useful options:

-m, –dry-runList steps that would be run without actually doing anything.

-t, –tasksList tasks that can be used as targets.

-b filename, –build-file filename

Page 439: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Use filename instead of the default build.xml. Also -file or -buildfile-Dproperty=value

Sets a property (similar to make’s variables)-q, –quiet

Suppress most output except for error messages.

gradle Tasks

Some built-in tasks that you can use as targets:

taskslist all available tasks

helpBy itself, explains how to get more help on using Gradle. With --task, ask for a description of a specific task.

initUsed to set up a new project using Gradle default properties.

wrapperAdds the Gradle wrapper to the project.

Usually accompanied by an option

--gradle-version versionNumber

to generate a wrapper for a specific version of gradle.

3 Build FilesThe gradle build file is a Groovy script, with Java-like syntax. Many of the more common Java API packages are imported automatically.

task upper << { String myName = "Steven Zeil"; println myName; println myName.toUpperCase(); }

If this is placed in build.gradle, then we can run it:

$ gradle upper :upperSteven Zeil

Page 440: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

STEVEN ZEIL BUILD SUCCESSFUL Total time: 1.747 secs $

3.1 Gradle TasksThe basic elements of a Gradle build file are tasks.

Gradle tasks can correspond Ant targets.

A Gradle task can perform multiple actions.

task upper { doLast { String myName = "Steven Zeil"; println myName; println myName.toUpperCase(); } }

Gradle tasks can correspond individual Ant tasks.

A Gradle task can perform multiple actions.

task copyResources (type: Copy) { from(file('src/main/resources')) into(file('target/classes')) }

In Ant, we would have used a <copy> task within a larger Ant target for this purpose.

3.2 Anatomy of a Task

3.2.1 The phases of a Gradle run

Before looking at the components of a task, we need to understand a bit about how Gradle works.

Page 441: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A Groovy function with parameters, e.g.,

void foo (int x, int y, int z) { ... }

can be called using positional arguments:

foo (12, 14, 0)

or by using named arguments:

A Gradle run occurs in four specific phases.

1. Initialization takes care of things that affect how Gradle itself will run. The most visible activity during this phase is loading Gradleplugins that add new behaviors.

2. Configuration involves collecting the build’s tasks, setting the properties of those tasks, and then deciding which tasks need to beexecuted and the order in which that will be done.

3. Execution is when the tasks that need to be executed get run.

4. Finalization covers any needed cleanup before the Gradle run ends.

Software developers will be mainly concerned with the middle two phases. For example, if we need to compile some Java source code for aproject, then we would want to configure that task by indicating the source code directory (or directories) and the destination for the generatedcode. With that information, Gradle can look to see if the .class files already exist from a prior run and whether the source code has beenmodified since then. Gradle can then decide whether or not the compilation task actually needs to be run this time. This decision isremembered during the execution phase when the task will or will not be run, accordingly.

3.2.2 Declaring tasks

A Gradle task can be declared as easily as:

task myTask

Some tasks may need parameters:

task copyResources (type: copy)

Page 442: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

foo (z: 0, x: 12, y: 14)

One advantage of the latter form is that you don’t have to know the order inwhich the parameters appeared in the function declaration. The named form iseven more useful when all or most of the parameters have default values and, inyour call, you only want to supply the value to one or two parameters for whichyou don’t like the defaults.

3.2.3 Configuring tasks

You can add code to be run at configuration time by putting it in { } brackets just after the task name:

task copyResources (type: Copy) copyResources { description = 'Copy resources into a directory from which they will be added to the Jar' from(file('src/main/resources')) into(file('target/classes')) }

You can combine a configuration with the task declaration:

task copyResources (type: Copy) { description = 'Copy resources into a directory from which they will be added to the Jar' from(file('src/main/resources')) into(file('target/classes')) }

3.2.4 Executable Behavior

Task types often have pre-defined behaviors.

For example, the Copy type copies files at execution time

task copyResources (type: Copy) { from(file('src/main/resources')) into(file('target/classes')) }

The from and into calls are performed at configuration time.

Page 443: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The Copytype actually copies the files at execution time.

gradle will check to see, at configuration time, if the files already exist at the destination and appear to be no olderthan the ones at thesource. If so, the copyResources task will be skipped at execution time.

3.2.5 Adding Executable Behavior

You can add code to be run at execution time by attaching it, within { }, using the doLast operation.

task copyResources (type: Copy) { from(file('src/main/resources')) into(file('target/classes')) doLast { println 'Copy has been done.' } }

or you can use that operation to add the code to an already-declared task object.

task copyResources (type: Copy) { from(file('src/main/resources')) into(file('target/classes')) } ⋮ copyResources.doLast { println 'Copy has been done.' }

3.3 Task Dependencies

task setupFormat task setupGraphics task setupSourceCode task generatePDFs (dependsOn: 'setup') generatePDFs.doLast { ➀ println 'in task generatePDFs' }

Page 444: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

task setup (dependsOn: ['setupFormat', 'setupGraphics', 'setupSourceCode']) setup.doLast { ➁ println 'in task setup' } task deploy (dependsOn: generatePDFs) deploy.doLast { println 'in task deploy' }

➀ : This line shows a dependency. Note that the task on which we aredepending has not been declared yet.

➁ : The [a, b, ...] notation introduces a Groovy array value.

The dependsOn parameter expects an array. But note that we did not usean array at ➀ . like most scripting languages, Groovy has lots of littleshortcuts designed to make like easier for programmers. At ➀ , we gotaway due to a shortcut that allows a single element to be passed as anarray of length 1.

Running this gives:

$ gradle deploy :setupFormat UP-TO-DATE:setupGraphics UP-TO-DATE:setupSourceCode UP-TO-DATE:setupin task setup :generatePDFsin task generatePDFs :deployin task deploy

3.3.1 Appending to Tasks

doLast (and doFirst) add actions to a task.

If we add the following to the previous script:

setup.doLast { println 'still in task setup' }

Page 445: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

$ gradle deploy :setupFormat UP-TO-DATE:setupGraphics UP-TO-DATE:setupSourceCode UP-TO-DATE:setupin task setup still in task setup:generatePDFsin task generatePDFs :deployin task deploy

3.4 TasksAt its heart, a build file is a collection of tasks and declarations.

A task is a Groovy function. It has a name, a body, and, optionally,

a list of dependenciesa conditiona human-readable description

The body of a task can contain multiple declarations and commands.

Gradle tasks are equivalent to Ant “targets”.

Ant tasks are handled as function calls in the body of a Gradle script.

3.4.1 Using Java within tasks

task playWithFiles { doLast { def files = file('src/main/data').listFiles().sort() ➀ files.each { File file -> ➁ if (file.isFile()) { ➂ def size = file.length() ➃ println "** $file.name has length " + size ➄ } } } }

Page 446: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

➀ There’s several things going on here. Let’s take it piece by piece.

def declares a variable. In this case, the variable is named files.

Like most scripting languages, Groovy (and therefore Gradle) is loosely (dynamically) typed, so we generally do not bother declaring variables bygiving their type, though that’s certainly possible.

Of course, that means that we have to pay close attention to the return values of our functions calls and operator uses if we, as programmers,want to know what kind of data will be stored in a variable.

file(...) returns a value of type File. In fact, this is a good old fashioned Java java.io.File, so we can look to the Java documentation to seewhat can be done with it.

One of the things we can do with it is to call listFiles(), which treats the File on the left of the ‘.’ as a directory and produces an array of Filerepresenting all the files in that directory.

And, knowing that listFiles() produces and array of files, it’s pretty obvious what .sort() would do.

We conclude that the variable files will hold a sorted list of all the files in directory src/main/data.

➁ The .each function is a Groovy function on arrays that allows us to iterate through the elements of the array, one at a time. On each iteration, we willstore the current array element in the variable file which we have declared, for clarity, as being of type File.

➂ Another thing we can do with Files is to check and see if they are “regular” files as opposed to being directories, links, or other special cases.

Again, this is not a special Gradle function, but is part of the normal Java behavior of a File class.

➃ The call to file.length() is just an ordinary Java function call.

➄ Several interesting things happen here.

The ‘$’ inside the quoted string allows us to request the replacement of a simple expression by its value. So we won’t actually print “file.name”.Instead the expressions file.name will be evaluated and the resulting value inserted into the string to be printed.

This “$” string substitution has been a common shortcut in scripting languages for decades.

Now, Java Files do not have a public data member called “name”, so the expression file.name would fail to compile in Java.

Java Files do, however, have a public function member getName(). And here we run into another one of those shortcuts that Groovy, as a scriptinglanguage, introduces. In Groovy, the notation x.data is considered a shorthand for x.getData() when we are trying to fetch data and forx.setData(..) when we are trying to store data. So the Groovy statement

x.data = y.member;

Page 447: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

is actually considered shorthand for

x.setData(y.getMember());

The + operator is the conventional Java String concatenation operator.

3.4.2 Using Ant within Tasks

The ant tasks library is included within gradle. So any useful ant task can be called:

task compile { doLast { // Compile src/.../*.java into bin/ ant.mkdir (dir: 'bin') ant.javac (srcdir: 'src/main/java', destdir: 'bin', debug: 'true', includeantruntime: 'false') ant.javac (srcdir: 'src/test/java', destdir: 'bin', debug: 'true', includeantruntime: 'false', classpath: testCompilePath) println 'compiled' } }

However, we probably would not use any of these:

Most Gradle users would use Java constructs for file manipulations, e.g., instead of

ant.mkdir(dir: 'bin')

they would write

file('bin').mkdir();

Gradle provides a Java plugin to handle compilation more easily.

Moreover, if we already had the Ant build file simpleBuild,xml, we could actually simply import it into a Gradle build:

ant.importBuild 'simpleBuild.xml' task build (dependsOn: 'deploy') .doLast { // "deploy" target from the Ant build file println 'Done' }

Page 448: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.5 Doing Maven-Like Things with GradleLike Maven, Gradle can be used to quickly create new projects with a standard directory/file layout and a standard sequence of build tasks. E.g.,

gradle init --type java-library

sets up a project with src/main/java and src/test/java directories.

4 Case Studies4.1 Simple Java BuildUsing the Java plugin, a basic build with unit tests is easy:

settings.gradle

// A simple Java project

This file needs to exist, but can be empty.

build.gradle

plugins { id 'java' ➀ } repositories { ➁ jcenter() }

➀ This loads and runs the Java plugin.

As long as our source code is arranged in the Apache/Android directory style, it will be handled correctly.

➁ The repositories section on is concerned with configuration management (covered later)

This is all you need to compile Java code stores in src/main/java.

If you have unit tests, we need to add a little more info.

Page 449: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

build.gradle

plugins { id 'java' } repositories { jcenter() } dependencies { testImplementation("junit:junit:4.12") ➀ testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.5.2") ➁ } test { ➂ useJUnit() }

The two sections at the end establish that

➀ When compiling our unit tests, we need to have the JUnit library, version 4.12, available.➁ When running our unit tests, we need the library junit-vintage-engine, version 5.5.2, available.➂ The code in the src/test directory contains our JUnit tests.

You can find this entire project, with the Gradle files, here.

4.2 Java Build with Code GenerationThis project adds a stage before compilation to generate some of the source code that then needs to be compiled.

The settings.gradle file is unchanged.

Here is the build.gradle file:

build.gradle

plugins { id 'java' id 'org.xbib.gradle.plugin.jflex' version '1.2.1' ➀ } repositories {

Page 450: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

jcenter() } dependencies { testImplementation("junit:junit:4.12") testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.5.2") / } test { useJUnit() }

➀ Here we apply the jflex plugin,which knows to run jflex on code located in src/main/jflex to generate Java source codeand to compile that generated Java source code along with the rest of the project.

You can find this entire project, with the Gradle files, here.

4.3 C++ Multi-project BuildA multi-project build in gradle is kept in a directory tree.

The top-most directory is the master project.

It contains the settings.gradle file.

Each subproject directory contains its own build.gradle file.

4.3.1 The master project

Any multi-project build in Gradle uses the settings.gradle file (usually in the common root containing the subproject directories) to identify the subprojects:

rootProject.name = 'manhattan' include "application", "geomlib"

In this case, we have two subprojects. One provides the executable, the other a library of ADTs, with unit tests, constituting the bulk of the code design.

There is no need for build.gradle file at this level, although it would be legal to provide one if you have project-level steps to be carried out.

4.3.2 The geomlib subproject

Page 451: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Of the two subprojects, the geomlib subproject is probably most interesting because it does the most. It compiles code into a library, then compiles and runsunit tests on that library code. By contrast, the application subproject only compiles code.

Here is the build.gradle file for the lib subproject:

build.gradle.lib.listing +

plugins { id 'cpp-library' id 'cpp-unit-test' } unitTest { binaries.whenElementKnown(CppTestExecutable) { binary -> if (binary.targetMachine.operatingSystemFamily.linux) { binary.linkTask.get().linkerArgs.add('-pthread') } } }

This listing starts off with two plugins, one for C++ compilation (into a reusable library) and the other for unit testing.

The unit test plugin can work with a variety of frameworks. Eventually, you should be able to load these frameworks as dependencies, much as you do inJava projects.

In this case, I am using CppUnitLite because it can be easily dropped into the directory with the unit tests.

Like most unit test frameworks, this one runs the tests in a separate thread (process). The unittest configuration here adds the required pthread librarywhen compiling under Linux.

4.3.3 The application subproject

The application subproject is simpler, because it only has one job to do – create an executable. Here it is:

build.gradle.exe.listing +

plugins { id 'cpp-application' } dependencies { implementation project(':geomlib') }

Page 452: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Very simple: we invoke the cpp-application plugin andIndicate that this depends on the :geomlib subproject

This dependency guarantees that the geomlib library will be constructed before this application is built and that it will be automatically included into theapplication compilation and link steps.

You can find this entire project, with the Gradle files, here.

Page 453: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Lab: Building with GradleSteven J Zeil

Last modified: Mar 7, 2020

Contents:1 Find That Project2 Compiling and Cleaning Up3 Restructuring Your Project4 Building with Gradle

This is a self-assessment activity to give you practice in working with the ant build manager. Feel free to share your problems, experiences, and choices in theForum.

1 Find That ProjectIn your assignment for the Unit Testing section of the course, you have been working with an ADT and accompanying tests.

We’ll use that code as a starting point for this lab. (If, for some reason, you don’t have working code for that assignment, you can use your project from thisearlier lab, but those tests were not very interesting.)

2 Compiling and Cleaning Up1. Copy the source code from your unit testing assignment, including both the instructor-provided code and your own unit tests, into a convenient directory.

2. Create a new Eclipse Java project at that directory. Remember to add the JUnit library to the build path of the new project.

3. Your code should compile under Eclipse to start with.

If your code was compiling but you have problem with this copied code, remember that a class packageName1.packageName2.className must be storedas .../packageName1/packageName2/className.java, where the “…” is the directory that serves as the common root of all of your source code.

4. Your project should include at least one unit test. Right-click on the .java file for such a test and select “Run As… JUnit test” to be sure that your testsrun.

Page 454: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3 Restructuring Your ProjectIn the lectures we talked about conventional ways of organizing the files that make up a project, including the Apache Foundation’s organization for Javaprojects.

Some important characteristics of this organization are

All the “source” files (code and data) written by the developers go into a src/ directory.All the files generated by the build process go into a target directory.The src directory is divided into src/main and src/test.

Files generated from src/main are assumed to become part of the final deliverable.Files generated from src/test are used during testing, but not included in the final deliverable.

The src/main and src/test directories are further divided according to programming language and/or “type” of data. Common subdirectories are java,data, and resources.

At a minimum, an Apache-style Java project should expect to have src/main/java and src/test/java directories.

Now we’ll look at restructuring a project to meet these guidelines.

1. Do this outside of Eclipse using normal operating system commands (command-line or GUI): Go to the directory holding your project. (If you aren’t surewhere that is, right-click on the project name in Eclipse, select Properties, and look at the Resource description.) Create src/main/java andsrc/test/java directories. Move your non-test Java files to src/main/java and move your Unit test Java files to src/test/java.

Remember that, in Java, package structure must match directory structure. So if your Java project includes a class MyClass in packagecs330.asst1, then you should currently have it in a location cs330/asst1/MyClass.java. When moving your code to the src/main/java andsrc/test/java directories, you need to keep that whole directory structure. In this example, you would wind up withsrc/main/java/cs330/asst1/MyClass.java.

2. Return to Eclipse, right-click on your project name, and select “Refresh”. Eclipse will discover your new directory structure, but won’t know what tomake of it. You’ll almost certainly wind up with error messages suggesting that your classes are in the wrong packages.

3. We need to tell Eclipse about our intentions to keep our source code in src/main/java and src/test/java. The key to doing that is the project BuildPath.

Right-click on any file of your project and select “Build path => Configure Build Path”. Go to the Source tab. This is where we tell Eclipse where to lookfor Java source code. Remove whatever folders are currently listed. Then add the folders src/main/java and src/test/java.

Click OK and, within a few seconds, you should see those error messages disappear.

4. One nice thing about adopting a standard project directory organization is that build files for that organization tend to be pretty similar. You can often re-use build files from one Apache-style project for another.

Page 455: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4 Building with GradleDo these steps from the command line, not in Eclipse:

1. Download and unpack this zip file in your project directory.

2. Use a text editor to create settings.gradle and build.gradle files mirroring the simple Java build

3. Check the build by asking for some basic information:

./gradlew tasks --all

(For Windows, omit the “./”).

4. Try running the actual build from the command line:

./gradlew build

(For Windows, omit the “./”).

Look through the build/ directory to see what was done.

5. Enter Eclipse, and delete your project from Eclipse (but do not delete the files).

6. Back in the command line, delete the files .project and .classpath.

(These are the Eclipse project settings from our earlier work with this directory. Since we are about to re-use this directory for a very different Eclipsesetup, it’s safer to start “fresh”.)

7. Right-click in the Eclipse Project Explorer area, and select “Import…”, Gradle, Gradle Project, and point it at the directory where your project waslocated.

For the gradle version, indicate that you are using the gradle wrapper.

Once you indicate that you are finished with the varios project settings, Eclipse will examine your settings.gradle and build.gradle files andconfigure its own settings accordingly. There may be a bit of a pause while Eclipse loads up-to-date versions of any third-party libraries (e.g., JUnit andHamcrest) listed in your build.grade file.

8. You should still be able to work in Eclipse and

edit your source code, getting instant response to many errors as you type.

Page 456: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

see your project rebuild whenever you save a changed .java file.be able to run the Java program and your unit tests.

Try making some small changes to the code and verify that everything still works from Eclipse as normal.

9. Right-click on the project name, select “Build Path … Configure Build Path”.

Examine the source directories that have been set up. You should see that Eclipse/Gradle have recognized your src/main/java and src/test/javadirectories.

Look at the Libraries tab. You should see a library “Project and External Dependencies”. Expanding that will show you libraries that Eclipse/Gradle havedownloaded and incorporated into your project.

We’ll talk more about how that happens in an upcoming lesson.

10. Now try launching your project build from the Gradle Tasks tab in the lower central panel.

11. One oddity that you might notice if you look at your project directory using the operating system is that you have two sets of compiled class paths, one inbin/ (caused by Eclipse compilation) and another in build/ (caused by Gradle compilations). It’s possible to force Eclipse to use build/ as well, butprobably not worth the effort.

Oddly, though, you probably can’t see the build directory in Eclipse because the Eclipse Project Explorer has several selective “filters” that it appliesbefore deciding what to show you.

Let’s change these filters so that you can see stuff that’s important.

At the top of the Project Explorer pane, look for a small triangle indicating a drop-down menu. Click on it and select “Filters …”

Remove the check marks from “.* resources” and from “Gradle Build Folder”.

12. Now that you can actually see your build/ folder, browse through it. Among other things, you should see a report generated that summarizes the unittests that you have run.

Try reading that report.

When the Eclipse Project Explorer is showing you an HTML file, you can usually view it by right-clicking on the file and seelecting Openwith... then System Editor, as most systems will define the system “editor” for HTML files as your default web browser.

13. You have now practiced running Gradle from the command line and from within Eclipse. You can use either as you prefer.

Page 457: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Remember, however, that whenever you use programs or commands outside of Eclipse to make changes to the project directory, you need torefresh your Eclipse project when you return to Eclipse. (Right-click on the project name and select “Refresh”.)

It’s often convenient to run Gradle from within Eclipse to do things not supported by or not so easy to do directly in Eclipse.

Try running the Gradle task “jar” within Eclipse. Refresh Can you find the generated .jar file. (Hint: Gradle builds everything somewhere within thebuild/ directory.)

Now try running the Gradle javadoctask within Eclipse. Find the newly generated HTML and browse it. (We’ll talk more about Javadoc in comingweeks.)

Page 458: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Software Configuration ManagementSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Problems Addressed by SCM

1.1 Codelines and Baselines2 Environment Management3 Build Management as an SCM Activity

3.1 Baselines Managed by Build Manager3.2 Simpler Project Structure

4 Version Control as an SCM Activity4.1 Codelines == Branches

5 Change Management5.1 Making Decisions5.2 Change Propagation

Abstract

Over time, a software system can exist in many versions:

revisions created as developers check in changesconfigurations intended for different hardware, operating system, or application environmentsreleases issued to users

which, if under continued support, may have separate tracks of revisions recording separate bug fixes

Software Configuration Management (SCM) is concerned with all of these.

Some of the tools we have already looked at (build management, version control) can help. But in SCM we need to look at the strategic application of those tothe management of many different software versions.

1 Problems Addressed by SCMSCM Activities

Version control

Page 459: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Build management

Environment management

Change management

The last two are new.

The first two we have discussed in isolation.

But the broader SCM context may alter how we use some of them

1.1 Codelines and BaselinesA codeline is a sequence of revisions of a configuration item

In essence, a branch

A baseline is a collection of component versions that make up a system.

1.1.1 Codelines and Baselines: Example

Page 460: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A baseline merges components that we have written (a version out of our codelines) with versions of 3rd party components that we employ.

1.1.2 Baselines

A major challenge of SCM is coping with multiple baselines that must

co-exist andbe actively maintained.

Major issues are

deciding when to “freeze” on a version of an imported librarytracking the transitive closure of dependencies from libraries that we directly depend upon

Page 461: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

finding a mutually compatible set of versions among all those external libraries

2 Environment ManagementCoping with the different environments in which the software may need to be installed and/or built.

Strategies includeseparate files

Easier to manage in the C/C++ world than in Javadeltas (patches)conditional compilation

Favored in the C/C++ worldHarder to support in Java world

dynamic loadingCommon in the Java worldOften controlled by “property files” that name modules to be employed for designated tasks in a given installation.

Example: the ODU Extract Project

Metadata extraction system, needed to support

One release version (thank the heavens)

Windows, Linux, & Mac platforms

Choice of 2 OCR programs (or none at all)

With local or network access to licensed copiesWith or without caching of OCR results

Statistical models trained on different document collections

Varying client requirements for data post-processing

Problem was not so much the number of choices as the combinatorics.

Third Party Libraries

Page 462: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Baselines may involve multiple 3rd-party libraries.

Different baselines may need differentlibraries.Or different versions of the same library

Luckily, there’s automated support for this aspect ofSCM, which we will cover separately.

3 Build Management as an SCM Activity

In an SCM context, we may have multiple baselines.

The build manager needs to be flexible enough to allow us to build each of those on command.

In some cases, using remote machines or virtual machines, to build all of them on (one) command.

Page 463: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.1 Baselines Managed by Build ManagerBuild manager is told what external libraries are needed

including desired versionsThis is easier to do once we get a handle on 3rd party library management.

Build manager may be responsible for collecting desired versions of both external and internal code from version control.

Build files are themselves managed as part of each version.

3.2 Simpler Project StructureIn current practice,

Large projects composed of multiple subprojects are discouraged

in favor of smaller, independent projects (e.g., one per original subproject)

Page 464: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A common rule of thumb is that one project should produce one product (e.g., a single Jar file)

Plus, perhaps, a source distribution.

and those are increasingly being replaced by centralized VC repositories

4 Version Control as an SCM ActivityWe’ve spent time looking at version control already.

We have lots of flexibility in terms of

Access to the version historyBranchesDistributed vs central access.

SCM challenges us to think strategically about how to exploit that flexibility.

4.1 Codelines == BranchesMain trunk moves forward in time

Each planned release is a branch from the trunk

continues forward through its maintenance lifetime

Page 465: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

5 Change Management

Page 466: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

When do proposed changes become an official part of a version?When do changes propogate multiple versions?

5.1 Making DecisionsIn large organizations, changes are approved by a Change Management Board.

E.g., the team working in an exploratory branch has demonstrated an attractive new feature.

Should we adopt it?If so, which of the version code lines should it be added to?

5.2 Change PropagationEven in smaller projects, the issue of change propagation across code lines needs to be kept in mind.

Page 467: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The whole “main trunk moves forward” idea presumes that most release changes are syncedinto the trunk:

As a practical matter, someone has to decide whether bug fixes in older versions can andshould be merged into later versions.

Page 468: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Managing Third-Party LibrariesSteven J Zeil

Last modified: Mar 30, 2020

Contents:1 Issues2 Basic Concepts

2.1 Repositories2.2 Identifying Packages2.3 Scopes

3 Adding Libraries to a Java Project in Different Build Managers3.1 Maven3.2 Ivy (ant)3.3 Gradle

4 Eclipse and Library Management4.1 Eclipse and Maven4.2 Eclipse and Ant/Ivy4.3 Eclipse and Gradle

5 Complicating Factors5.1 Plug-ins5.2 Publishing5.3 Login Credentials

6 What about C++?6.1 What’s Holding Us Up?6.2 On the Horizon

Abstract

Modern build managers provide support for

importing 3rd-party libraries,managing dependencies among those libraries, andpublishing our own project deliverables.

so that all of these can be handled quickly and efficiently as part of the normal build.

Page 469: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1 IssuesBaselines may include multiple 3rd-party libraries.

We may rely on specific version of our chosen libaries.

Older versions may not provide the functions we need, or may have bugs that would affect our project.Newer versions may alter or remove functions we have been using, or introduce new bugs that affect our project.

Those libraries may require other libraries.

Page 470: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The library versions that we require might onloy be compatible with specific versions of those other libraries.

Example: Report Accumulator

A project of mine, this page lists the 3rd party libraries required by the project.

The page lists various stages of the build.

Expand each stage to see the libraries that I requested for that stage

E.g., for testCompile, I requested JUnit 4.12 8 Which in turned needed hamcrest-core 1.3

For the findbugs stage, I requested findbugs 3.0.1

And that required multiple libraries, including asm-commons 5.0.2asm-commons 5.0.2 required asm-tree 5.0.2asm-tree 4.0.2 asm-asm 5.0.2

2 Basic Concepts2.1 RepositoriesA repository is a collection of packages (usually libraries) and metadata about packages

The metadata identifiesthe package,the versions available,their dependencies on other packages, andthe location from which the package may be downloaded.

In some cases, the metadata may point to other repositories as the actual download location.

2.1.1 Common Java Repositories

The Java world is dominated by

Maven Central (a.k.a ibiblio)

JCenter

Page 471: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Try searching each of these for junit

Notice range of versions availableSelect one (e.g., 4.12)

Explore the snippets for the various build managersThese are instructions on how to add the library to your build.

2.1.2 Local Repositories

It’s common for development organizations to host their own repository.

A place to put their own deliverablesA “cache” to speed access to libraries commonly used by many developers within the organization.

preserve older versions needed for a project baseline

Local repositories can be

elaborate (Artifactory )

These may support a “pass-through” to Maven Central and/or JCenter for libraries that have not yet been locally cached.

or little more than a file drop

2.2 Identifying PackagesPackages are typically identified by

The group or organization

Generally given in the Java style of a reversed URL, e.g. org.apache.ant, edu.odu.cs.extractLike some Hollywood celebrities, some organizations become big enough stars to be simply known by a single name, e.g., junit

The artifact name

E.g., junit, hamcrest-core, apache-commons

Version number

Single versions are identified exactly: 4.12Depending on the build manger being used, you may be able to specify things like

4.11+: 4.11 or laterlatest.integration: latest official release

Page 472: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1.2-SNAPSHOT: a version under development. The stapshot modifier serves as a notice that the actual package may be updated without achange in version number.

2.3 ScopesNot every library that your project needs is needed all of the time.

If your “main code” uses a library, you would need that during compilation, testing, and possibly packaging.Libraries like junit would only be needed when compiling and running the unit tests.Libraries like findbugs, checkstyle (discussed later in the semester) are only used during report generation.A build manager may support “plug-ins” that extend or modify the build process. These plug-ins are typically packaged much like other 3rd-partylibraries, but are needed much earlier in the build process.

So build managers allow you to import libraries in selected scopes which indicate when the library is actually needed.

This affects

Whether a library is downloaded or updated during a given build.Java CLASSPATH and other settings made available to the build steps.

3 Adding Libraries to a Java Project in Different Build Managers3.1 Maven

3.1.1 Specifying a Dependency

Examine the pom.xml file and look for the dependencies section.

You’ll see something like

<dependencies> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependencies>

Could also say [4.12,] to get versions 4.12 or greater

Page 473: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.1.2 Fetching Dependencies

When the build is run (e.g. mvn package):

Maven does a transitive search over the dependencies for a project

Tries to find a mutually compatible set of versionsHelps if you give it some flexibility

Maven then downloads the required libraries automatically

Downloaded libraries are cached (e.g., ~/.m2)

3.1.3 Transitive Dependencies

How does Maven know whether junit itself depends on other libraries?

Here is the actual published content for Junit 4.12.

The .pom file is the metadata.

Look inside. Search for <dependencies>. You’ll find

<dependencies> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> <version>1.3</version> <scope>compile</scope> </dependencies>

This is the same kind of info that we put into our own pom.xml file

And is, presumably, taken from the pom.xml that the JUnit team used to maintain their builds.Publishing the dependency information along with the libraries leads to an accumulated base of information on library dependencies.

3.1.4 Choosing Repositories

Technically, our project has two repositories

a remote repository, at ibiblioa local repository holding my cache

Page 474: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Team projects will often employ an intermediate shared repository

reduce cache duplicationprovide a mechanism for managing subproject modulesprovide a common storage area for libraries not available on ibibliopreserve older versions needed for a project baseline

3.1.5 Example: specifying a repository

In pom.xml:

<repositories> <repository> <snapshots> <enabled>false</enabled> </snapshots> <id>central</id> <name>libs-release</name> <url>http://archive350.cs.odu.edu:8080/artifactory/libs-release</url> </repository> </repositories>

We could then, for example, import early versions of zipdiff and trilead-ssh that were part of the baseline for the Extract projectAt the time they were added to the project baseline, they were not in the remote Maven repositoryAs time has passed, those libraries were added, but have started with versions later than the project baseline

3.2 Ivy (ant)

YAAP1 , Ivy adds the dependency management features pioneered by Maven to ant

Technically can run as a standalone application, but really the ant integration is key.

Use is similar to the dependencies/repositories portion of Maven POMs

Ivy can retrieve from and publish to the established Maven repositories

3.2.1 Getting Started with Ivy

The Ivy project pages include some “magic” ant code to * download the latest version of Ivy * add a resolve-ivy task to be invoked before you compile yourcode * This task will download any 3rd-party dependencies and add them to your compilation classpaths.

Page 475: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3.2.2 Specifying our Desired Libraries

We list the libraries our project needs in a separate ivy.xml file

<ivy-module version="2.0"> <dependencies> <dependency org="de.jflex" name="jflex" rev="1.4.3"/> <dependency org="junit" name="junit" rev="4.10"/> </dependencies></ivy-module>

This should look familiar to the section from the Maven pom:

<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> </dependencies>

3.2.3 Invoking Ivy

Once Ivy is installed, we can invoke it:

build.xml2.listing +

<project name="codeAnnotation" basedir="." default="build" xmlns:ivy="antlib:org.apache.ivy.ant"> ⋮ <target name="resolve-ivy" depends="install-ivy"> <ivy:resolve/> ➀ <ivy:cachepath pathid="ivy.path" /> ➁ <taskdef classpath="JFlex.jar" classname="JFlex.anttask.JFlexTask" name="jflex" /> ➂ </target> <target name="generateSource" depends="resolve-ivy"> <mkdir dir="target/gen/java"/> <jflex file="src/main/jflex/code2html.flex" ➃ destdir="target/gen/java"/>

Page 476: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<jflex file="src/main/jflex/code2tex.flex" destdir="target/gen/java"/> ⋮

➀ The ivy:resolve task fetches the libraries we need.

They will be kept in a cache (~/.ivy).

➁ This creates an Ant path named ivy.path containing the list of all libraries fetched.

Includes both the ones we explicitly named in our ivy.xml and ones that those depended upon.

➂ Here we can bind the task name for the JFlex library that we have loaded,

➃ enabling us to later use the <jflex ... > task

Making the build depend on the Ivy sequence guarantees that the library availability will be managed at each build

3.2.4 Ivy & Repositories

Ivy can use most maven repositories.

Choice of repositories is controlled by an ivysettings.xml file.

By default, uses the same ibiblio service that is Maven’s default.

An example of an ivysettings.xml file:

ivysettings.xml.listing +

<?xml version="1.0" encoding="UTF-8"?><ivy-settings> <settings defaultResolver="default" /> <resolvers> <chain name="default"> ➀ <ibiblio name="central" m2compatible="true"/> ➁ </chain> </resolvers></ivy-settings>

➀ A “chain” means that we want Ivy to search these repositories in sequence.

In this case, I only have one thing in the chain, but for other projects I may add additional repositories.

Page 477: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

➁ Look in the Maven Central archive.

3.2.5 Ivy & Eclipse

The developers of Ivy provide an Eclipse plugin, IvyDE.

Allows you to add a “Library” to your Eclipse project’s build pathThis library holds everything that Ivy fetches based upon your ivy.xml file.

3.3 GradleAs is often the case, gradle tends to provide simpler syntax to do much the same things as Maven and Ant.

3.3.1 Selecting libraries in Gradle

In build.gradle:

apply plugin: 'java' ⋮ repositories { jcenter() ➀ // Use my own CS dept repo ivy { ➁ url 'https://www.cs.odu.edu/~zeil/ivyrepo' } } dependencies { ➂ implementation 'net.sf.saxon:saxon-dom:8.7+' testImplementation 'junit:junit:4.12' testRuntimeOnly 'edu.odu.cs.zeil:reportAccumulator:1.1+'

}

Here you see both the choice of libraries ➂ and of repositories ➀, ➁.

The dependencies indicate

Page 478: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The scope (e.g., testCompile, which actually includes compiling and running of the unit tests)

The package, specified as organization:package:versionNumber

Scopes in Gradle

dependencies { ➂ implementation 'net.sf.saxon:saxon-dom:8.7+' testImplementation 'junit:junit:4.12' testRuntimeOnly 'edu.odu.cs.zeil:reportAccumulator:1.1+'

}

If project P depends on library L, then the most common scopes recognized by Gradle are:

apiP requires L to compile and to run. If P is itself a library, anyone who uses P must have L available to compile and run as well.

Generally this means that some class declared in L is used as a parameter or a return type by some public function in P.

implementationP requires L to compile and run the code, but this is hidden from users of P.

testImplementationP requires L to compile and run unit tests.

classpathP uses L as a plugin.

There are other variations possible: “Implementation” can be replaced by “CompileOnly” and “RuntomeOnly”, but those will be fairly uncommon.

In older Gradle examples (including a lot of mine in this course) you will see the scopes * compile * runTime * testCompile* testRuntime

These are now deprecated.

4 Eclipse and Library ManagementEach of the build/library managers we have discussed have support in Eclipse

May provide special editors for editing the build manager configuration files.

Page 479: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Provide ways to launch the build manager from within Eclipse

Sometimes it’s easier to launch separately in a separate window, e.g., from the command line from the Gradle GUI mode.

Remember to “refresh” the project in Eclipse afterwards

Most importantly, allows Eclipse Java projects to use any 3rd-party libraries fetched by the build/library manager.

Otherwise the built-in Eclipse compilation and smart-editing features would mistakenly believe that your code was full of references to non-existent classes and funnctions.

May allow some management of the cache of old libraries.

4.1 Eclipse and MavenCan also hope for convenience functions

In particular, POM editors

Two plugins currently

m2eclipse, older pluginEclipse IAM

Allows you to create new Maven projects or to import existing ones into Eclipse.

4.2 Eclipse and Ant/IvySupport for Ant is built-in to Eclipse

The developers of Ivy provide an Eclipse plugin, IvyDE.

Allows you to add a “Library” to your Eclipse project’s build path

This library holds everything that Ivy fetches based upon your ivy.xml file.

4.3 Eclipse and GradleEclipse has various Gradle plugins available.

Page 480: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The most popular seems to be the BuildShip package, now standard in most Eclipse distributions.

Allows import (only) of existing Gradle projects

Allows launching Gradle from within Eclipse

from a special Gradle Tasks panel, not from the package explorer.

Allows Eclipse Java projects to find 3rd-party libraries loaded by Gradle.

After any change to the dependencies in build.gradle, you must right-click on build.gradle and select Gradle -> refresh Gradleproject.

Eclipse re-reads your build.gradle file and obtains the desired libraries.

5 Complicating Factors5.1 Plug-insPlug-ins to build managers modify the build process itself

unlike “normal” 3rd-party libraries that affect how the code is compiled and run, but not when or whether the compilation steps take place.

Consequently, plug-ins generally need to be fetched and processed at the very beginning of a build, much earlier than most 3rd-party libraries.

Nonetheless, it is convenient to use the same dependency/repository scheme to publish and import plug-ins.

5.1.1 Separate but similar

Plug-ins to build managers are generally handled separately from other items, though the syntax is often similar.

unlike “normal” 3rd-party libraries that affect how the code is compiled and run, but not when or whether the compilation steps take place.

Consequently, plug-ins generally need to be fetched and processed at the very beginning of a build, much earlier than most 3rd-party libraries.

Nonetheless, it is convenient to use the same dependency/repository scheme to publish and import plug-ins.

5.1.2 Separate but similar

Page 481: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Plug-ins to build managers are generally handled separately from other items, though the syntax is often similar.

For example, in gradle, plug-ins are retrieved from repositories specified in a pluginManagement section in settings.gradle:

pluginManagement { repositories { jcenter() ivy { // for url 'https://www.cs.odu.edu/~zeil/ivyrepo' } } }

The syntax and options within the pluginManagement area are almost identical to the way we handle normal package repositories.

Then we load the plugins from a plugins section in build.gradle:

plugins { id 'java' id 'edu.odu.cs.report_accumulator' version '1.3' }

Maven has a similar approach, isolating plug-ins in a <plugins> section.

5.2 PublishingPublishing artifacts to a repository is also supported by maven, Ant/Ivy, & Gradle.

Typically more complicated.

mainly because most repositories are open to download, but require login credentials to upload.

Example: in Gradle build.xml

publishing { publications { ivyJava(IvyPublication) { organisation 'edu.odu.cs.zeil' module 'cowem-plugin' revision project.version descriptor.status = 'integration' // milestone, release descriptor.branch = 'v1'

Page 482: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

from components.java } } repositories { ivy { name 'ivyRepo' url 'sftp://atria.cs.odu.edu:22/home/zeil/secure_html/ivyrepo' // Readable via https://www.cs.odu.edu/~zeil/ivyrepo credentials { ⋮ } } } }

5.3 Login CredentialsProviding login credentials to a build is problematic.

Can’t insert passwords into the build file, because the build file will be checked in to version control, so we would be publishing our credentials in plainview, for all time!

A common work-around is to store a few build “properties” in a file in the user’s home directory, not kept as part of the package version control.

Example: in Gradle build.xml

// Credentials are loaded from ~/.gradle/gradle.properties if(project.hasProperty("ivyRepoUser")){ ➀ ext.ivyRepoUser = "$ivyRepoUser"; } else { ext.ivyRepoUser = "user"; } if(project.hasProperty("ivyRepoPass")){ ext.ivyRepoPass = "$ivyRepoPass"; } else { ext.ivyRepoPass = "password"; } ⋮ publishing { ⋮ credentials { ➁ username project.ivyRepoUser

Page 483: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

password project.ivyRepoPass } ⋮ }

➀ looks to see if properties ivyRepoUser and ivyRepoPass were loaded from ~/.gradle/gradle.properties. If so, it adds them as “extension”properties of the current gradle project.

➁ passes those new extension properties as login credentials to a repository.

If the person running the build di not have a ~/.gradle/gradle.properties or it did not contain the properties ivyRepoUser andivyRepoPassproeprties, then attempted uploads to the repository would use a default username and password that would, presumably, fail.

6 What about C++?Sadly, the situation for C++ is somewhat more complicated.

Should C++ libraries be deployed as source or binaries?

Binary library formats (e.g., DLL’s in windows, .a or .so in *nix) are OS-specific.Developers generally need header (.h) files as well as the compiled code if they are to compile their own applications.

There are Operating System-dependent solutions for deploying binaries.

Windows install files can check to see if required libraries for an application are already present and fetch and install them if necessary.Linux repositories provide a similar mechanism.

Even more than OS-dependent, these are distribution dependent.Different variants of Linux use different repository formats

These solutions work for deploying applications but not so well for developers.

6.1 What’s Holding Us Up?We Don’t Have Anything Equivalent to Maven Central for C++

There’s no recognized central place to publish and find open source C++ libraries.

No standard for what such a library would look like.

Compiled binaries would have to be provided for multiple OS variants.

Page 484: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Partly, that’s because we don’t have build managers that would take advantage of such libraries if they existed.

We Don’t Have Anything Equivalent to Maven/Ivy/Gradle Dependency Management for C++

There are no build managers capable of processing dependencies for C++ while simultaneously factoring in the platform-specific requirements.

Who would write such a tool when there’s no central repositories where such libraries can be stored?

Which Came First, the Chicken or the Egg?

Who wants to set up repositories without build managers that can use them?

Who wants to write such build managers if there are no repositories that they could work with?

6.2 On the HorizonGradle seems to be paying serious attention to C/C++ build support.

Gradle’s existing Java package management might be leveraged into C++ support.

Conan is an attempt to provide a packaging standard for C++ library repositories.

Good news: the same company that hosts JCenter is also hosting Conan artifacts.Bad news: Only a handful of rather specialized projects have been contributed so far (as of Jan 2018).

Encouraging news: the number is growing steadily (as of Oct 2019)Gradle support for this is still in the works.

In mid-summer of 2019, the Gradle project released a heavily revised set of C++ plugins, which greatly simplify building C++ with Gradle.

These include provisions for downloading both binary and source code libraries.

Not clear how stable these are, but it’s a promising sign.

1: Yet Another Apache Project

Page 485: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Managing Code VariantsSteven J Zeil

Last modified: Mar 30, 2020

Contents:1 Problems2 AUTOCONF

2.1 Compiling Software the Unix Way2.2 Generating The configure Script2.3 Example

3 Dynamic Loading

1 ProblemsCode Variations

Environment management, (previously identified as common SCM problems):

Coping with change in

hardware environmentsoftware environment

Can lead to need for variant code to support different configurations

The Sad Story of C/C++ Portability

Both C and C++ existed as popular languages long before being standardized

Widespread variations in the “system” headers

Even after standardization, many common functions are not standardized

GUIsmulti-threading and distributed operations

Page 486: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

network communcations

Even things covered by the standard aren’t covered in enough detail

C Portability Quiz

How would you declare an integer counter capable of holding non-negative values up to one million? Up to one billion?

C90 requires sizeof(short) sizeof(int) sizeof(long)

Notice that’s , not <

A char must hold a “natural” byte (minimum addressable unit) on the machine architecture.

The C99 specification added long long and set minimum sizes as

char 8short 16int 16long 32long long 64

C++ Portability Quiz

How would you declare an integer counter capable of holding non-negative values up to one million? Up to one billion?

The C++ standard followed C90 (not 99!) until C++11

sizeof(short) sizeof(int) sizeof(long)

C++11 adds the C99 standards

Coping With Variants in the C/C++ World

Configuration headers used to define symbols describing selected variants, e.g.,

config.h +

#ifndef CONFIG_STD#define CONFIG_STD

≤ ≤

≤ ≤

Page 487: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

//// AlgAE Configuration file// // Currently recognizes g++, version 2.7.2 for Unix and 2.8.0 for GnuWin32// MS Visual C++, version 5.0// // Define this if the compiler does not support reassignment of iostream// buffers via the function rdbuf(streambuf&)#undef __bad_rdbuf__ #ifdef __GNUG__ /* Compiler is gcc/g++ */ #define MEM_INCL <mem.h> #define USING_STD#define STD#define USE_FORK #ifdef __CYGWIN32__ /* This is the GnuWin32 port for Windows 95/NT #define USE_WINSOCK #else /* This is some other port of g++, probably a Unix system. */#endif #elif defined(_MSC_VER)/* compiler is Microsoft Visual C++ */ #define MEM_INCL <alloc.h> #define USING_STD using namespace std;#define STD std:: #define MEMDC#define __bad_rdbuf__#define USE_WINSOCK #else #pragma warning "Possible configuration error: Compiler is not recognized." #define MEM_INCL <mem.h>

Page 488: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

#endif #endif

Code uses symbols defined in there

direct substitution, e.g.

#include MEM

loads <alloc.h> or <mem.h>

or conditionally

#ifdef USE_WINSOCK#include <winsock2.h>#else#include <netinet/in.h>#include <sys/socket.h>#endif

2 AUTOCONF2.1 Compiling Software the Unix WayIf you’ve ever installed a Unix/Linux package from a source distribution, you’ve probably gotten used to the two-step process:

./configure make install

The configure script runs a series of tests on the compilation environment, e.g.,

operating systemcompiler nameavailability of selected libraries/header filesavailability and/or behavior of selected functions

Page 489: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Produces a Makefile and a configuration header config.h based upon the test results

Source code may use conditional compilation based on the header to select appropriate code

2.2 Generating The configure ScriptA rough outline:

1. Create a configure.ac2. Set up config.h.in (template for eventual config.h file)3. Set up Makefile.am4. Set up files NEWS README AUTHORS ChangeLog5. Run autoreconf

2.3 Example

2.3.1 1. Create a configure.ac

AC_INIT(cppSpreadsheet, 1.0, [email protected])AC_PREREQ([2.68]) ➀ AM_INIT_AUTOMAKE([1.16 foreign no-define])AC_CONFIG_HEADERS([config.h]) AC_PROG_CXX ➁ AC_CONFIG_FILES([Makefile]) AC_OUTPUT

➀ Make sure autoconf is at least version 2.68➁ Search for a C++ compiler and make sure one is available.Some common tests that might be added before the final AC_OUTPUT include:

AC_CHECK_FILE(file): check to see if a file existsAC_CHECK_LIB(library): check to see if a library is already installedAC_SEARCH_LIBS(function): search for an installed library that provides this functionAC_FUNC_MALLOC: check to see if the malloc function exists and appears to behave as expected.

This is one of a whole slew of AC_FUNC_… options

2.3.2 Preparing the templates

2: Set up config.h.in (template for eventual config.h file)

Page 490: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3: Set up Makefile.am

AM_INIT_AUTOMAKE([1.10 no-define foreign]) bin_PROGRAMS = testssheet testssheet_SOURCES=testssheet.cpp exprparser.cpp tokenizer.cpp exprfactory.cpp expression.cpp \ cellname.cpp numericnode.cpp stringnode.cpp cellrefnode.cpp negatenode.cpp \ absnode.cpp sqrtnode.cpp sumnode.cpp lessnode.cpp lesseqnode.cpp \ greaternode.cpp greatereqnode.cpp equalnode.cpp notequalnode.cpp plusnode.cpp \ subtractnode.cpp timesnode.cpp dividesnode.cpp ifnode.cpp \ numvalue.cpp strvalue.cpp errvalue.cpp spreadsheet.cpp cell.cpp \ observable.cpp observerptrseq.cpp cellptrseq.cpp cellnameseq.cpp \ absnode.h control.h lessnode.h ssi.h \ binarynode.h dividesnode.h minusnode.h ssview.h \ cell.h elementseq.h negatenode.h streamtok.h \ celllistenerseq.h equalnode.h notequalnode.h stringnode.h \ cellname0.h errvalue.h numericnode.h strvalue.h \ cellname.h expression.h numvalue.h subtractnode.h \ cellnameseq.h exprfactory.h observable.h sumnode.h \ cellptrseq.h exprparser.h observer.h timesnode.h \ cellrange.h greatereqnode.h observerptrseq.h unaryexpr.h \ cellrefnode.h greaternode.h plusnode.h unarynode.h \ clipboard.h ifnode.h spreadsheet.h unittest.h \ constantnode.h lesseqnode.h sqrtnode.h value.h

2.3.3 Generating the configure Script

4: touch NEWS README AUTHORS ChangeLog

or create real versions of these.

5: run autoreconf --force --install

Runs the sequence of programs: aclocal autoconf autoheader automakeCreates config.h.in Makefile.in & configure

Alternatives

imake for X code

3 Dynamic Loading

Page 491: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

autoconf is C/C++-centric

The configure approach relies heavily on conditional compilation features.

Common in C++

Only in Java via non-standard techniques

Java: Abstraction

Java programs are more likely varied be altering entire classes at a time.

For example:

public abstract class OCRLauncher extends Thread { /** * Launch an OCR process to convert the input * PDF into some kind of File of OCR output. * * @param inputPDFfile The PDF file to be converted to IDM (XML) * @param outputFile The raw OCR output * @return */ public abstract boolean convertPDFtoOCR (File inputPDFfile, File outputFile) throws Exception; /** * Convert a file of OCR output into IDM * * @param inputOCRfile * * @return XML (IDM) document */ public abstract Document convertOCRtoIDM (File inputOCRfile) throws Exception; }

This class has distinct implementations for different OCR programs that might be installed on the running system.

Configuration via Property Files

Page 492: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A property file, loaded at run time, specifies which class is actually desired:

input.OCRLauncherClass=edu.odu.cs.extract.input.OCRBatchLauncher input.OCRProgram=OCR input.OCRBatch=Batch input.ocr.in_dir=c:/Luratech/ocr_in input.ocr.out_dir=c:/Luratech/ocr_out

Reflection: Dynamic Loading

And the desired class is loaded dynamically:

String OCRLauncherName = p.getProperty(Properties.Names.OCR_LAUNCH_CLASS); Class<?> ocrLauncherClass = Class.forName(OCRLauncherName); ocr = (OCRLauncher)ocrLauncherClass.newInstance(); idmDoc = ocr.convertOCRtoIDM(inputOCR);

Page 493: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Documentation and Documentation GeneratorsSteven J Zeil

Last modified: Apr 1, 2020

Contents:1 Source Code Documentation

1.1 Comments1.2 Self-Documenting Code1.3 Charting

2 API Documentation2.1 javadoc2.2 doxygen2.3 Other API Documentation Generators

… because everyone loves writing documentation.

1 Source Code Documentation1.1 Comments

widely used

widely abused

1.1.1 Do Comments Matter?

McConnell has a good & balanced discussion on this.

Source code commenting is often a crutch to hide

poor naminga failure to extract code blocks into recognizable functionspoor designlack of quality tools (version control, issue tracking, source formatters)

Page 494: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Still useful for

Explaining why a thing is being doneDocumenting a pseudo-code based designCross-referencing related items

Modern focus has shifted considerably away from commenting bodies towards API documentation.

1.1.2 Which is better?

double m; // mean averagedouble s; // standard deviation

double meanAverage double standardDeviation

1.1.3 Which is better?

Page 495: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

// Sum up the datadouble sum = 0.0; double sumSquares = 0.0; // Add up the sumsfor (double d: scores) { sum += d; sumSquares += d*d; } // Compute the average and standard// deviationdouble meanAverage = sum / numScores; double standardDeviation = sqrt ((sumSquares - numScores*sum*sum) /(numScores - 1.0)); // Subtract the average from each data// item and divide by the standard// deviation.for (int i = 0; i < numScores; ++i) { scores[i] = (scores[i] - meanAverage) / standardDeviation; }

// Compute summary statisticsdouble sum = 0.0; double sumSquares = 0.0; for (double d: scores) { sum += d; sumSquares += d*d; } double meanAverage = sum / numScores; double standardDeviation = sqrt ((sumSquares - numScores*sum*sum) / (numScores - 1.0)); // Normalize the scoresfor (int i = 0; i < numScores; ++i) { scores[i] = (scores[i] - meanAverage) / standardDeviation; }

1.1.4 Which is better?

Page 496: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

// Compute summary statisticsdouble sum = 0.0; double sumSquares = 0.0; for (double d: scores) { sum += d; sumSquares += d*d; } double meanAverage = sum / numScores; double standardDeviation = sqrt ((sumSquares - numScores*sum*sum) /(numScores - 1.0)); // Normalize the scoresfor (int i = 0; i < numScores; ++i) scores[i] = (scores[i] - meanAverage) / standardDeviation;

void computeSummaryStatistics ( const double* scores, // inputs int numScores, double& meanAverage, // outputs double& standardDeviation) { double sum = 0.0; double sumSquares = 0.0; for (double d: scores) { sum += d; sumSquares += d*d; } meanAverage = sum / numScores; standardDeviation = sqrt ((sumSquares - numScores*sum*sum) /(numScores - 1.0)); } void normalizeData (double* data, int numData, double center, double spread) { for (int i = 0; i < numData; ++i) data[i] = (data[i] - center) / spread; } ⋮ double meanAverage; double standardDeviation; computeSummaryStatistics (scores, numScores, meanAverage, standardDeviation); normalizeData (scores, numScores, meanAverage, standardDeviation);

1.1.5 Which is better?

Page 497: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

void computeSummaryStatistics ( const double* scores, // inputs int numScores, double& meanAverage, // outputs double& standardDeviation) { double sum = 0.0; double sumSquares = 0.0; for (double d: scores) { sum += d; sumSquares += d*d; } meanAverage = sum / numScores; standardDeviation = sqrt ((sumSquares - numScores*sum*sum) /(numScores - 1.0)); } void normalizeData (double* data, int numData, double center, double spread) { for (int i = 0; i < numData; ++i) data[i] = (data[i] - center) / spread; } ⋮ double meanAverage; double standardDeviation; computeSummaryStatistics (scores, numScores, meanAverage, standardDeviation); normalizeData (scores, numScores, meanAverage, standardDeviation);

void computeSummaryStatistics ( const double* scores, // inputs int numScores, double& meanAverage, // outputs double& standardDeviation) { double sum = accumulate( scores, scores+numScores); double sumSquares = accumulate( scores, scores+numScores, [](double x, double y) {return x + y*y;}); meanAverage = sum / numScores; standardDeviation = sqrt ((sumSquares - numScores*sum*sum) /(numScores - 1.0)); } ⋮ // Normalize the scoresdouble meanAverage; double standardDeviation; computeSummaryStatistics (scores, numScores, meanAverage, standardDeviation); transform ( scores, scores+numScores, scores, [] (double d) { return (d - meanAverage) / standardDeviation});

1.1.6 Kinds of Comments

Repeat of the code

Useless

Page 498: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Explanation of the code

Only useful if the code is confusing

In which case, first priority should be to simplify the code.

Markers

notes not intended to be left in final code

If standardized, useful

e.g., // TODO in Eclipse

flagged in editoreasily searched for

Summary of the code

applied to entire code “paragraphs”useful to allow easy skimming of the code

Description of intent

similar to summary, but describes problem rather than solution

Information that cannot be expressed in the code

e.g., authors, copyright, date of modification

1.2 Self-Documenting CodeSelf-Documenting code relies on good programming style to perform most of the documentation.

“the Holy Grail of legibility” (McConnell)

1.2.1 Characteristics of Self-Documenting Code

Classes

Does the class’s interface present a consistent abstraction?

Page 499: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Is the class well named, and does its name describe its central purpose?

Does the class’s interface make obvious how you should use the class?

Is the class’s interface abstract enough that you don’t have to think about how its services are implemented? Can you treat the class as a blackbox?

Routines

Does each routine’s name describe exactly what the routine does?

Does each routine perform one well-defined task?

Have all parts of each routine that would benefit from being put into their own routines been put into their own routines?

Is each routine’s interface obvious and clear?

Data Names

Are type names descriptive enough to help document data declarations?

Are variables named well?

Are variables used only for the purpose for which they’re named?

Are loop counters given more informative names than i, j, and k?

Are well-named enumerated types used instead of makeshift flags or boolean variables?

Are named constants used instead of magic numbers or magic strings?

Do naming conventions distinguish among type names, enumerated types, named constants, local variables, class variables, and globalvariables?

Data Organization

Are extra variables used for clarity when needed?

Are references to variables close together?

Are data types simple so that they minimize complexity?

Is complicated data accessed through abstract access routines (abstract data types)?

Control

Page 500: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Is the nominal path through the code clear?

Are related statements grouped together?

Have relatively independent groups of statements been packaged into their own routines?

Does the normal case follow the if rather than the else?

Are control structures simple so that they minimize complexity?

Does each loop perform one and only one function, as a well-defined routine would?

Is nesting minimized?

Have boolean expressions been simplified by using additional boolean variables, boolean functions, and decision tables?

Layout

Does the program’s layout show its logical structure?

Design

Is the code straightforward, and does it avoid cleverness?

Are implementation details hidden as much as possible?

Is the program written in terms of the problem domain as much as possible rather than in terms of computer-science or programming-language structures?

(McConnell, ch 32)

1.3 ChartingHow many forms of software documentation charting do you know?

Control Flow

Flowcharts

Nassi-Schneidermann Charts

State diagrams

Page 501: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

UML interaction diagramsModule relationships

Structure (call) charts

Data-Flow Diagrams

SADT (Structured Analysis and Design Technique)E-RUML class relationship diagrams

1.3.1 From Code to Charts

For as long as people have been writing source code, they’ve been looking for ways to ease the effort of documenting that code.

Often after-the-fact

Earliest examples were automatic flowchart generators

Generating flowcharts from source code.

Raw results were poor qualityBut still could be claimed to satisfy client requirements

As flowcharts declined in popularity, so did the demand for these tools.

Still offered in reverse engineering tools ( e.g. )

Flowchart synced to code viewerHuman retitles blocks as “understanding” of the code progresses

1.3.2 From Charts to Code

A hallmark of so-called CASE (Computer-Aided Software Engineering) systems

Modern versions generate class declarations from UML class diagrams

2 API DocumentationAPI documentation tools are now more common

Reflect modern emphasis on re-usable interfaces

Page 502: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Combine info from

a (limited) language parser

Extracts info about module/function structure and function parameters

and specially formatted blocks of comments embedded in the source code

Encourages updating comments as code is modified

Comments become a legitimately useful tool for application writers.

Application writers have less need to access actual code.

Generate linked documents to facilitate browsing of referenced type names and other entities

Some IDEs understand this markup as well and use it enhance “live” help while editing code.

2.1 javadocPerhaps the best known tool in this category

part of the standard Java distribution

achieved prominence when Sun used it to document the Java “standard library”.

E.g., 1.6, 1.8

2.1.1 Javadoc Comments

Javadoc markup is enclosed in comments delineated by /** ... */

And therefore processed as normal comments by the Java compiler.

A comment block precedes the entity that it describes

e.g., This page is generated from this source code.

In addition to “free-form” text, can contain special markup

Common Javadoc Markup

Page 503: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

@author authorName

@version versionNumber

@param name description

@return description

@throws exceptionClassName description

@see crossReference

Running javadoc

Command line

javadoc -d destinationDir -sourcepath sourceCodeDir \ -link http://docs.oracle.com/javase/7/docs/api/

Can add multiple source paths, links to external librariesCan also specify which packages from source code to document

Eclipse: Project ⇒ Generate Javadoc ...

2.1.2 JavaDoc and build managers

Ant

Ant has a javadoc task among its default task set.

A typical invocation might be:

<javadoc packagenames="edu.odu.cs.*" destdir="target/javadoc" classpathref="javadoc.classpath" Author="yes" Version="yes" Use="yes" defaultexcludes="yes"> <fileset dir="." defaultexcludes="yes"> <include name="extractor/src/main/java/**" /> <exclude name="**/*.html" /> </fileset> <doctitle><![CDATA[<h1>ODU CS Extract Project</h1>]]></doctitle>

Page 504: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

</javadoc>

Gradle

Gradle provides a javadoc plugin that provides a javadoc task.

Here is the full build.gradle for a simple Java build with Javadoc generation.

Click to reveal +

Page 505: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

plugins { id 'java' id 'javadoc' ➀ } repositories { jcenter() } dependencies { testImplementation("junit:junit:4.12") testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.5.2") } test { useJUnit() ignoreFailures = true } javadoc { ➁ options.with { links 'https://docs.oracle.com/javase/8/docs/api/', 'gradle/javadocs/jdk' } failOnError = false; ➂ } build.dependsOn javadoc ➃

➀ use the javadoc plugin.➁ Include links to the online Java API documentation.➂ Don’t stop the build just because javadoc finds a problem➃ Tell Gradle to run the javadoc task before the build task.

2.2 doxygenthe most popular API generator for C/C++

Also works with Objective-C, C#, Java, IDL, Python, PHP, VHDL, and FORTRAN

Markup is essentially identical to javadoc

Internal formatting available via Markdown

Output can be HTML, LaTeX, or RTF

Page 506: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Can also generate

various non-quite-UML diagramsand hyperlinked source code

Running doxygen

Command line

doxygen configFile

The config file can contain any of a bewildering set of options in typical property-file style:

PROJECT_NAME = C++ SpreadsheetINPUT = src/modelOUTPUT_DIRECTORY = target/docEXTRACT_ALL = YESCLASS_DIAGRAMS = YESGENERATE_HTML = YESGENERATE_LATEX = YESUSE_PDFLATEX = YES

Eclipse: Eclox plugin

Ant task for doxygen

Gradle plugins for doxygen (untried)

2.3 Other API Documentation GeneratorsBecause a documentation generator needs to module and function structure and function parameters, a distinct parser is needed for each programming language.

This leads to a variety of language-specific tools, e.g.,

jsDoc for Javascript

YARD for Ruby

sandcastle for .Net

Could not parse reporting...skipping

Page 507: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Program Analysis ToolsSteven J Zeil

Last modified: Apr 6, 2020

Contents:1 Representing Programs

1.1 Abstract Syntax Trees (ASTs)1.2 Control Flow Graphs

2 Style and Anomaly Checking2.1 Lint2.2 Static Analysis by Compilers2.3 CheckStyle2.4 SpotBugs2.5 PMD

3 Reverse-Engineering Tools3.1 Reverse Compilers3.2 Java Obfuscators3.3 Obfuscation Example

4 Dynamic Analysis Tools4.1 Pointer/Memory Errors4.2 Profilers

Abstract

In this lesson we look at a variety of code analysis tools available to the practicing software developer. These include static analysis tools that examine codewithout executing it, and dynamic analysis tools that monitor code while it is being run on tests or in operation.

We will look at the kinds of information that developers can obtain from these tools, the potential value offered by this information, and how such tools can beintegrated into an automated build or a continuous integration setup.

Classifying Analysis Tools

Static Analysis

style checkersdata flow analysis

Page 508: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Dynamic Analysis

Memory use monitorsProfilers

Analysis Tools and Compilers

Analysis tools, particularly static, share a great deal with compilers

Need to parse code & understand at least some language smeantics

Data flow techniques originated in compiler optimization

1 Representing ProgramsMost static analysis is based upon one of these graphs

That’s “graphs” in the discrete mathematics (CS 381) or data structures (CS 361) sense: a collection of nodes connected by edges, not the sense of points plottedon X-Y axes.

Abstract syntax trees

Control Flow Graphs

1.1 Abstract Syntax Trees (ASTs)

Output of a language parser

Simpler than parse trees

Generally viewed as a generalization of operator-applied-to-operands

Abstract Syntax Trees (cont.)

Page 509: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

ASTs can be applied to larger constructions than just expressions

Abstract Syntax Trees (cont.)

In fact, generally reduce entire program or compilation unit to one AST

1.1.1 Abstract Syntax Graphs

In most programming languages, any given variable name (e.g., i, x) could actually refer to many different objects depending upon the scope rules of thelanguage.The semantic analysis portion of a compiler pairs uses of variable names with the corresponding declarations

Page 510: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What we have left is no longer a tree, but a graph.

1.2 Control Flow GraphsRepresent each executable statement in the code as a node,

with edges connecting nodes that can be executed one after another.Nodes for conditional statements have two or more outgoing edges.

1.2.1 Sample CFG

01: procedure SQRT (Q, A, B: in float;02: X: out float);03: // Compute X = square root of Q,04: // given that A <= X <= B

Page 511: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

05: X1, F1, F2, H: float;06: begin07: X1 := A;08: X2 := B;09: F1 := Q - X1**210: H := X2 - X1;11: while (ABS(H) >= 0.001) loop12: F2 := Q - X2**2;13: H := - F2 * ((X2-X1)/(F2-F1));14: X1 := X2;15: X2 := X2 + H;16: F1 := F217: end loop;18: X := (X1 + X2) / 2.;19: end SQRT;

Page 512: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Simplifying CFGs: Basic Blocks

procedure SQRT (Q, A, B: in float; // node 0 X: out float); // Compute X = square root of Q,// given that A <= X <= B X1, F1, F2, H: float; begin X1 := A; X2 := B; // node 1 F1 := Q - X1**2 H := X2 - X1; while (ABS(H) >= 0.001) loop // node 2 F2 := Q - X2**2; H := - F2 * ((X2-X1)/(F2-F1)); X1 := X2; // node 3 X2 := X2 + H; F1 := F2 end loop; X := (X1 + X2) / 2.; // node 4 end SQRT; // node 5

1.2.2 Data Flow Analysis

All data-flow information is obtained by propagating data flow markers through the program.

The usual markers are

di(x) : a definition of variable x (any location where x is assigned a value) at node ir<sub>i</sub>(x): a reference to x (any location where the value of x is used) at node iu<sub>i</sub>(x): an undefinition of x (any location where x becomes undefined/illegal) at node i

Page 513: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Data flow problems are solved by propagating markers around a control flow graph

Data-Flow Annotated CFG

procedure SQRT (Q, A, B: in float; // node 0 X: out float); // Compute X = square root of Q,// given that A <= X <= B X1, F1, F2, H: float; begin X1 := A; X2 := B; // node 1 F1 := Q - X1**2 H := X2 - X1; while (ABS(H) >= 0.001) loop // node 2 F2 := Q - X2**2; H := - F2 * ((X2-X1)/(F2-F1)); X1 := X2; // node 3 X2 := X2 + H; F1 := F2 end loop; X := (X1 + X2) / 2.; // node 4 end SQRT; // node 5

1.2.3 Reaching Definitions

A definition di(x) reaches a node nj iff there exists a path from ni to nj on which x is neither defined nor undefined.

What definitions reach the reference to X1 in node 4?

What definitions reach the reference to H in node 2?

Page 514: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1.2.4 Data Flow Anomalies

The reaching definitions problem can be used to detect anomolous patterns that may reflect errors.

ur anomalies: if an undefinition of a variable reaches a reference of the same variable

dd anomalies: if a definition of a variable reaches a definition of the same variable

du anomalies: if a definition of a variable reaches an undefinition of the same variable

1.2.5 Available Expressions

An expression e is available at a node n iff every path from the start of the program to n evaluates e, and iff, after the last evaluation of e on each such path,there are no subsequent definitions or undefinitions to the variables in e.

procedure SQRT (Q, A, B: in float; // node 0 X: out float); // Compute X = square root of Q,// given that A <= X <= B X1, F1, F2, H: float; begin

Page 515: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

X1 := A; X2 := B; // node 1 F1 := Q - X1**2 H := X2 - X1; while (ABS(H) >= 0.001) loop // node 2 F2 := Q - X2**2; H := - F2 * ((X2-X1)/(F2-F1)); X1 := X2; // node 3 X2 := X2 + H; F1 := F2 end loop; X := (X1 + X2) / 2.; // node 4 end SQRT; // node 5

Is the expression X2 - X1 available at the start of node 3?

At the end of node 3?

Same questions for Q - X2**2

1.2.6 Live Variables

A variable x is live at node n iff there exists a path starting at n along which x is used without prior redefinition.

In what nodes in H live?

In what nodes is X1 live?

What does this tell you about memory allocation within this function?

Page 516: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1.2.7 Data Flow and Optimization

Optimization Technique Data-Flow InformationConstant Propagation reachCopy Propagation reachElimination of Common Subexpressions availableDead Code Elimination live, reachRegister Allocation liveAnomaly Detection reachCode Motion reach

2 Style and Anomaly CheckingA common form of static analysis:

2.1 LintPerhaps the first such tool to be widely used, lint (1979) became a staple tool for C programmers.

Page 517: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Combines static analysis with style recommendations, e.g.,

data flow anomalies

potential arithmetic overflow

e.g., storing an int calculation in a char

conditional statements with constant values

potential = versus == confusion

Is there room for lint-like tools?

lint was a response, in part, to the weak capabilities of early C compilers

Much of what lint does is now handled by optimizing compilers

However compilers seldom do cross-module or even cross-function analysis

2.2 Static Analysis by CompilersOver time, compilers offer more and more static analysis features.

E.g., GNU g++

One caution is that these are often not turned on by default, but need to be added as command line flags.

IDEs often do not use these flags by default.

Analysis Options for g++

g++ offers several “collections” flags that turn on multiple warnings (which could have been turned on individually).

You explored these in an earlier lab.

-Wall: warnings that GNU considers “useful” and “easily avoidable”

Examples include:

out of bound accesses to arrays, (when compiled with -O2)

Page 518: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

use of C++11 features when the explicit option for these has not been supplieduse of char in array subscriptsabuse of enumeration types in comparisonsbad formats in printfpossibly uninitialized variables

-Wextra: warnings that GNU considers “useful” but that can create false positives that can be hard to avoid.

Examples:

empty loop and if bodies,comparisons between signed and unsigned integers,unused function parameters.

-pedantic: warnings required by ISO C++ as for non-standard code.

e.g., non-standard file extensions

-Weffc++: warnings about violations of Scott Meyer’s Effective C++

Examples:

Failing to implement your own version of the copy constructor and assignment operator for classes that have dynamic allocation.operator= implementations that fail to return *this,the use of assignment rather than initialization within constructors

2.3 CheckStylecheckstyle is a tool for enforcing Java coding standards.

Focus is on the more cosmetic aspects of coding, e.g.:

Non-empty Javadoc comments for all classes and members.No * imports.Lines, function bodies, files not too long.{ } used around even single-statement loop bodies and if-then-else bodies.Whitespace used uniformly.

Sample report

Can be run via

Page 519: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

AntMavenGradleeclipse

Checkstyle messages appear as warnings/errors in the Java editor.

2.3.1 Example: Adding Checkstyle to gradle

In build.gradle:

apply plugin: 'checkstyle' ⋮ checkstyle { ignoreFailures = true ➀ showViolations = false } ⋮ tasks.withType(Checkstyle) { ➁ reports { html.destination project.file("build/reports/checkstyle/main.html") } } checkstyleTest.enabled = false ➂

➀ ignoreFailures determines whether the gradle build should stop when CheckStyle reports a problem.

Usually, that’s not a good idea because not all CheckStyle problems are “real” – some are “false positives”.

➁ This section specifies where the report file should be stored.

Usually this should be somewhere in build/reports/.

➂ Suppresses running CheckStyle on code in src/test/java.

Report is generated on target check.

Which checks are run and which are suppressed is determined by a file config/checkstyle/checkstyle.xml, which is generally modified from one ofthese.

2.4 SpotBugsUnlike Checkstyle, SpotBugs goes well beyond cosmetics:

Page 520: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

“Bugs” categorized as

Correctness bug: an apparent coding mistakeBad Practice: violations of recommended coding practices.Dodgy: code that is “confusing, anomalous, or written in a way that leads itself to errors”

Bugs are also given “priorities” (p1, p2, p3 from high to low)

Sample report

2.4.1 SpotBugs in Gradle

In build.gradle:

buildscript { repositories { jcenter() maven { url "https://plugins.gradle.org/m2/" // for spotbugs } } dependencies { ⋮ classpath "gradle.plugin.com.github.spotbugs:gradlePlugin:1.6.0" } } apply plugin: 'com.github.spotbugs' spotbugsMain { ignoreFailures = true effort = 'max' reportLevel = 'medium' reports { xml.enabled = false html.enabled = true } } spotbugsTest.enabled = false

2.5 PMDAnother good tool for finding non-cosmetic problems in your code:

Page 521: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

PMD, source analysis for Java, JavaScript, XSL

CPD, “copy-paste-detector” for many programming languages

Can find large repeated code segments that might be better pulled out into a single function.

Works on source code

Sample reports (PMD & CPD)

Can be run via

AntMavenEclipse (see below)Gradle

2.5.1 PMD Reports

Configured by selecting “rule set” modules

Otherwise, appears to lack categories & priorities

Reports provide cross reference to source location

2.5.2 Example: Adding PMD to gradle

In build.gradle:

apply plugin: 'pmd' ⋮ pmd { ignoreFailures = true consoleOutput = false } pmdTest.enabled = false

Report is generated on target check.

2.5.3 Example: Adding PMD to Eclipse

Open the Eclipse Marketplace (Help menu) and search for “pmd”Select the “pmd-eclipse-plugin” and install

Page 522: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Open your Java project Properties and look for PMD.Select “Enable PMD”, then “Apply and Close”.

Look at all the colorful flags!

Open the PMD perspective (Window -> Perspective -> Open Perspective) to examine and manage messages.

You can ask for Details, remove a flag, mark a statement as approved under review, or suppress a rule entirely.

2.5.4 Customizing PMD

In Gradle and Eclipse, you customize by giving your own ruleset, like this one.

Gradle:

pmd { ruleSetFiles = ["config/pmd/ruleset.xml"] }

Removing a Rule

A common thing to do in a custom ruleset is to remove a rule entirely:

<rule ref="rulesets/java/comments.xml"> <exclude name="CommentSize"/></rule>

(This rule is well-intentioned, but tends to flag Javadoc-style comments that often have good reason to exceed it’s limit of 6 lines per comment.)

Modifying a Rule

<rule ref="category/java/codestyle.xml/ClassNamingConventions"> <properties> <property name="utilityClassPattern" value="[A-Z][a-zA-Z0-9]+"/> </properties></rule>

This rule defaults to insisting that all Java “utility” classes (ones that have no constructors) should have names ending with “Helper” or “Util”.

Page 523: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Often violated by main classes.Often given more specific names indicating what kind of help they provide e.g., “Factory” or “Wrapper”Always violated by unit tests.

Excluding Source Code

<ruleset ⋮> <description>PMD rule set - java applications</description> <exclude-pattern>.*/src/test/java/.*</exclude-pattern>

I don’t find PMD checks on Unit test code to be particularly useful.

Unit test code is often deliberately rougher than the application code.

3 Reverse-Engineering ToolsReverse engineering makes heavy use of static analysis, and is even more closely tied to compiler technology than the tools we have looked at so far.

3.1 Reverse Compilersa.k.a. “uncompilers”

Generate source code from object code

Originally clunky & more of a curiosity than usable tools

Improvements based on“deep” knowledge of compilers (aided by increasingly limited field of available compilers)Information-rich object codes (e.g., Java bytecode formats)

Legitimate uses include

reverse-engineeringgenerating input for source-based analysis tools

But also great tools for plagiarism

Java and Decompilation

Page 524: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Java is a particularly friendly field for decompilersRich object code formatNearly monopolistic compiler suite

3.1.1 Example of Java Decompilation

For example, I might write the following code:

void drawGraphics(Graphics g, Point[] pts) { double xMin = pts[0].x; double xMax = pts[0].x; double yMin = pts[0].y; double yMax = pts[0].y;

If I compile this with the -g debugging option on (which saves variable names and other internal information so that a debugger can access them), andrun any of several well-known decompilers, I would get back the same code, with only formatting changes.

If I compile this code without debugging info, one well-known decompiler would give me this:

void drawGraphics(Graphics g, Point[] pts) { double d0 = pts[0].x; double d1 = pts[0].x; double d2 = pts[0].y; double d3 = pts[0].y;

Compiled Java .class files always preserve the API info.

Defending Against Decompilers

Options for “protecting” programs compiled in Java:gjc: compile into native code with a far less popular compilerobfuscators…

3.2 Java ObfuscatorsWork by a combination of

Renaming variables, functions, and classes to meaningless, innocuous, and very similar name sets

Page 525: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Challenge is to preserve those names of entry points needed to execute a program or applet or make calls upon a library’s public API

Stripping away debugging information (e.g., source code file names and line numbers associated with blocks of code)

Applying optimization techniques to reduce code size while also confusing the object-to-source mapping

Replacing some expressions by calls to “dummy” functions that actually simply compute the replaced expression.

3.3 Obfuscation ExampleExample, given the compiled code from

void drawGraphics(Graphics g, Point[] pts) { double xMin = pts[0].x; double xMax = pts[0].x; double yMin = pts[0].y; double yMax = pts[0].y;

the obfuscator yguard will rewrite the code so that the best that a decompiler could produce is:

void a(Graphics a, Point[] b) { double d0; double d1; double d2; double d3; _mthfor(d0, _mthdo(b, 0)); _mthfor(d1, _mthdo(b, 0)); _mthfor(d2, _mthif(b, 0)); _mthfor(d3, _mthif(b, 0));

4 Dynamic Analysis ToolsNot all useful analysis can be done statically

Profiling

Memory leaks, corruption, etc.

Data structure abuse

Page 526: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Abusing Data Structures

Traditionally, the C++ standard library does not check for common abuses such as over-filling and array or accessing non-existent elements

Various authors have filled in with “checking” implementations of the library for use during testing and debugging

In a sense, the assert command of C++ and Java is the language’s own extension mechanism for such checks.

4.1 Pointer/Memory ErrorsMemory Abuse

Pointer errors in C++ are both common and frustrating

Traditionally unchecked by standard run-time systems

Monitors can be added to help catch these

In C++, link in a replacement for malloc & free

How to Catch Pointer Errors

Use fenceposts around allocated blocks of memory

check for unchanged fenceposts to detect over-writesCheck for fenceposts before a delete to detect attempts to delete addresses other than the start of an allocated block

Add tracking info to allocated blocks indicating location of the allocation call

Scan heap at end of program for unrecovered blocks of memoryReport on locations from which those were allocated

Add a “freed” bit to allocated blocks that is cleared when first allocated and set when the block is freed

Detect when a block is freed twice

Memory Analysis Tools

Purify is a well-known commercial (pricey) tool

At the other end of the spectrum, LeakTracer is a small, simple, but capable open source package that I’ve used for many years

Page 527: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Works with gcc/g++/gdb compiler suiteSample of Leaktracer Output +

Page 528: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Gathered 8 (8 unique) points of data. (gdb) Allocations: 1 / Size: 360x80608e6 is in NullArcableInstance::NullArcableInstance(void) (Machine.cc:40). 39 public: 40 NullArcableInstance() : ArcableInstance(new NullArcable) {} Allocations: 1 / Size: 80x8055b02 is in init_types(void) (Type.cc:119). 118 void init_types() { 119 Type::Integer = new IntegerType; Allocations: 1 / Size: 132 (new[]) 0x805f4ab is in Hashtable<NativeCallable, String, false, true>::Hashtable(unsigned int) (ea/h/Hashtable.h:15). 14 Hashtable (uint _size = 32) : size(_size), count(0) { 15 table = new List<E, own> [size];

Newer versions of g++ and clang offer Address sanitizer and Leak Sanitizer

Other sanitizers are worth checking out.

4.2 ProfilersProfilers provide info on where a program is speding most of its execution time

May express measurements in

Elapsed timeNumber of executions

Granularity may be at level of

functionsindividual lines of code

Measurement may be via

Probes inserted into codeStatistical sampling of CPU program counter register

Profiling Tools

Page 529: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

gprof for C/C++, part of the GNU compiler suite

Refer back to earlier lesson on statement and branch coveragegprof is, essentially, the generalization of gcov

jvisualm for Java, part of the Java SDK

Provides multiple monitoring tools, including both CPU and memory profiling

Page 530: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Continuous IntegrationSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Big Builds2 Continuous Integration

2.1 Key Ideas2.2 Continuous Integration Systems

3 Case study: Jenkins3.1 Projects on Jenkins

4 Case study: gitlab-ci4.1 gitlab-ci setup

5 gitlab-ci vs Jenkins6 Case Study: Enhanced reporting

6.1 Generating Graphs6.2 Generating the Data6.3 Report Accumulator

7 Related ideas

Abstract

In continuous integration, the practices of version control, automated building, automated configuration, and automated testing are combined so that, as changesare checked in to the version control repository, the system is automatically rebuilt, tested, reports generated, and the results posted to a project website.

1 Big BuildsThink of everything we have started to put into our automated builds:

fetching and setup of 3rd party librariesstatic analysiscompilationunit testingdocumentation generationstatic analysis reports

Page 531: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

packaging of artifactsdeployment/publication of artifactsupdating of project website

and, coming up, we will want to expand our testing to include

integration testingtest coverage reportingsystem testing

There’s a danger of the builds becoming so unwieldy and slow that programmers will start to look for ways to circumvent steps,

Do We Need to do All of Those Steps, All of the Time?

One possible breakdown:

Every build Occasionalfetching and setup of 3rd party libraries documentation generationstatic analysis static analysis reportscompilation deployment/publication of artifactsunit testing updating of project websitepackaging of artifacts integration testing

test coverage reportingsystem testing

This should provide someone actively working on a specific module/story the info they need, deferring some of the more time-consuming build activities.

How do we divide these steps in the build?

Even the “occasional” activities may be done many times over the history of a project.

So we want to keep them automated, both for ease of performing them and to ensure they are performed consistently each time.

With make/ant/maven, we can have different targets/goals for the frequent and the occasional cases.

But we have to remember to use the proper targets at the right time.Maybe not a bid deal…

But there’s an opportunity here to do something much more interesting…

Page 532: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2 Continuous IntegrationWhen we combine

Automated testing (unit, integration, system, and regression)Centralized version control

or distributed VC with a central “official” repositoryAutomated builds, capable of running tests, running analysis tools, and publishing the results on a project web site

we can rebuild and retest automatically as developers check in changes.

2.1 Key IdeasOur project should have the characteristics:

Version control with a clearly identified main branch or set of main development branches.

Automated build is set up as usual.

Developers commit frequently (maybe many times per day)

Commits to “private” branches (or local copies of a distributed repository) are ignored.Every commit of a tracked branch to the main repository is built on a separate server

The build includes all integration-related tasks (for early detection of integration problems.Can also include more time-consuming reporting tasks.

Testing is done, ideally, in a clone of the production environment(s)

May differ from development environmentsProbably not checked frequently under normal practiceCan use multiple remote machine “runners” to provide varying target operating systems and environments.

Make the results highly visible

2.1.1 Advantages

Integration problems caught early and fixed fastavoids “integration hell”

Immediate testing of all changesEmphasis on frequent check-ins encourages modularity

Page 533: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Visible code quality metrics motivate developers.

2.1.2 Disadvantages

Initial setup effort to set upLevel of sophistication required of team to put build, configuration mgmt, testing, reporting, into an automated build

2.2 Continuous Integration SystemsA CI system consists of a server/manager and one or more runners…

2.2.1 The Continuous Integration Server

A continuous integration server is a network-accessible machine that

Can be told of development projects under way, including

location & access info to version control (VC) repositorywhich branch(es) to watchhow to build the projectwhat reports are produced by the build

Monitors, in some fashion, the VC repository for commits

When a commit (to a monitored branch) takes place, the CI server notifies one or more runners.

2.2.2 Continuous Integration Runners

A CI runner (a.k.a., nodes or slave processors) is a process on a machine that

has the the necessary compilers and other tools for building a project.

is managed by the CI server.

When notified by the server, the runner

1. Checks out a designated branch of a project from its version control system.

2. Runs the build.

3. Publishes reports on the results of the build(s).

Page 534: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Runners are usually separate machines from the CI server.

A CI project may launch several different runners, each with a different configuration environment (e.g., different operating systems) to test the buildunder multiple configurations.

3 Case study: JenkinsJenkins is a popular CI server.

The CS Dept runs its own Jenkins server

An example of a Jenkins project

3.1 Projects on JenkinsWhen you set up a project on Jenkins you must supply:

Basic project info:

name and description,public/private,who can access.

Version control:

What kind of version control is used,URL and access info to check out a copy of the project.

Build management:

What build manager is used,where the build file can be found within the project directorieswhat target/goal to use with the build

(I usually add a special “jenkins” target to my Ant build.xml files.)

Which of Jenkin’s nodes can be used for the build.

Reporting

Page 535: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What reports Jenkins should publish.Where in your project directories the raw data for these reports can be found.

3.1.1 Jenkins and Project Reports

Many report-generating programs (e.g., JUnit, FindBugs, etc.) have separate “collection” and “reporting” stages.

Typically the collection step writes raw data out in an XML format.

Normally, you then run a separate task to reformat that XML into HTML or some other readable format.

Jenkins, however, has its own formatting functions for many common reports.

Among other things, these often add “historical” or “trend” reporting on how the collected data has varied over a period of time.

4 Case study: gitlab-cigitlab-ci is a CI server integrated into Gitlab.

Project build status is integrated into the version control activity reports,

Example

Click on Green checkmarks and Red X’s to see successful and failed builds.

Setup is generally easier if your project is already hosted on Gitlab.

4.1 gitlab-ci setup1. Projects must activate gitlab-ci by designating a runner, generally on a remote machine under the developer’s control.

You can have multiple runners. For example, you could have a Linux runner, a Windows 10 runner, and a MacOS runner.

2. Then add a file .gitlab-ci.yml to the repository root directory.

This is a YAML script that gets run after each new commit.

Script can limit which branches it applies to

4.1.1 An example of .gitlab-ci.yml

Page 536: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

stages: - build - test - deploy build-job: tags: - e-3208 stage: build script: - eval $(ssh-agent -s -t 600) - ssh-add <(echo "$REPORTS_SSH_KEY") - cd codeCompCommon - ./gradlew build deployReports only: - master artifacts: paths: - codeCompCommon/build/libs/codeCompCommon-1.3.jar - README.md

tags: identifies the runner to be selected.script: gives the build commands to be run on the runner machine.only: limits these runs to checkins on the “master” branch.artifacts: lists files that will be kept after the run and made available for downloading from the GitLab project page.

4.1.2 The script dissected

script: - eval $(ssh-agent -s -t 600) ➀ - ssh-add <(echo "$REPORTS_SSH_KEY") ➁ - cd codeCompCommon ➂ - ./gradlew build deployReports ➃

1. This line launches an ssh key agent. The -t 600 option limits this agent to a maximum of 600 seconds before it shuts itself down.2. We know the ssh-add command as a way to add private ssh keys to the agent.

In this case, the text of the (passphrase-free) private key is being supplied by GitLab as a secret project variable REPORTS_SSH_KEY.

These are created as part of the project settings and visible only to project “masters”.

They provide a useful way to add private keys and other secret credentials without putting them into the repository files where anyone might beable to download them.

Page 537: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3. cd into the subproject directory containing the code and the Gradle files

4. Run the build with targets build and deployReports.

We’ll look at deployReports shortly.

5 gitlab-ci vs JenkinsReporting

Jenkins provides fancier reporting options. It composes a nice-looking project summary page.

Such activities must be scripted as part of the build to work in gitlab-ci.

Discussed later.

Flexibility

Jenkins has a definite Java bias.

gitlab-ci can run any language you can script a build for.

Setup

Jenkins setup can be confusing.

gitlab-ci setup is easier, but requires a properly setup remote runner.

Runners:

Jenkins allows remote runners, which are easily shared among projects.gitlab-ci requires remote runners, often requiring each project to set up their own.

6 Case Study: Enhanced reportingGoal: add project website pages with reports from analysis tools and trend information (historical graphs) similar to those offered by Jenkins.

We will build on the example of our JBake-generated website.

An example of a page we would like to generate is this PMD report page.

Page 538: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

6.1 Generating GraphsHighcharts is a Javascript package that can generate plots from data captured in CSV (Comma-Separated-Values) format.

For example, the plot on this page is generated from a file pmd.csv that looks like:

pmd,Violations 2019-03-23T14:30,22.0 2019-03-23T14:33,22.0 2019-03-23T15:21,22.0 2019-03-23T15:45,22.0 2019-03-24T21:59,22.0 2019-03-31T19:48,22.0 2019-03-31T20:26,22.0 2019-04-03T20:42,11.0

Each line (after the headers) represents one data point in the chart.

Highcharts requires a bit of Javascript to inject a chart into an HTML div element.

We load the Highcharts code in our website header

header.ftl.listing +

<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"/> <title><#if (content.title)??><#escape x as x?xml>${content.title}</#escape><#else>codecentric</#if></title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content=""> <meta name="keywords" content=""> <meta name="generator" content="JBake"> <link href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>css/base.css" rel="stylesheet"> <link href="<#if (content.rootpath)??>${content.rootpath}<#else></#if>css/projectReports.css" rel="stylesheet"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js" type="text/javascript"></script> <script src="https://code.highcharts.com/highcharts.js"></script> <script src="https://code.highcharts.com/modules/data.js"></script> <script src="<#if (content.rootpath)??>${content.rootpath}<#else></#if>js/projectReports.js"></script> </head> <body>

Page 539: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

<div id="mainBody">

This includes my own Javascript file to make it easier to share the code among several pages.

projectReports.js.listing +

/* * Register a div in the webpage as a HighCharts (http://www.highcharts.com/) chart * portraying a series of data in a CSV file */ /* register1 * For CSV files containing a single series of data. Column A contains the * Build numbers used as x values, column B the y values. * * @param graphName The id of the div to hold this chart. * @param csvURL URL to the .csv file * @param title Title for this chart. * @param yAxistitle Title for the Y axis. (Series title is taken from * row 1 of the CSV file). */ function register1(graphName, csvURL, title, yAxisTitle) { var divName = "#" + graphName; $(document).ready(function() { $.get(csvURL, function(csv) { $(divName).highcharts({ chart: { type: 'area' }, data: { csv: csv }, title: { text: title }, yAxis: { title: { text: yAxisTitle } }, xAxis: { title: { text: "Build #" } }, plotOptions: {

Page 540: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

series: { stacking: 'normal' } }, series: [{ color: "#0000cc" } ] }); }); }); } /* register2 * For CSV files containing two series of data. Column A contains the * Build numbers used as x values, columns B and C the y values. * * @param graphName The id of the div to hold this chart. * @param csvURL URL to the .csv file * @param title Title for this chart. * @param yAxistitle Title for the Y axis. (Series title is taken from * row 1 of the CSV file). */ function register2(graphName, csvURL, title, yAxisTitle) { var divName = "#" + graphName; $(document).ready(function() { $.get(csvURL, function(csv) { $(divName).highcharts({ chart: { type: 'area' }, data: { csv: csv }, title: { text: title }, yAxis: { title: { text: yAxisTitle } }, xAxis: { title: { text: "Build #" } },

Page 541: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

plotOptions: { series: { stacking: 'normal' } }, series: [{ color: "#009933" }, { color: "#cc0000" } ] }); }); }); }

Which makes for a reasonably straightforward content page:

pmd.html.listing +

title=CodeCompCommon PMD Report type=page status=published ~~~~~~ </p><div class=reportGraphs> <div id="theGraph" class="graph">PMD</div> ➀ </div> <iframe class="docFrame" src="pmd/main.html"> </iframe> ➁ <script type="text/javascript"> register1("theGraph", "pmd.csv", "PMD", "Warnings"); ➂ </script> <p>

1. This is the div that will be replaced by the chart.2. The body of the report.

This is very similar to the way we loaded our Javadoc and other reports earlier.

3. This calls my Javascript function, which in turn calls the Highchart functions, to schedule replacement of the above div by a chart derived from thedata in pmd.csv.

Page 542: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

6.2 Generating the DataWhere does the data for the plots come from?

Individual data points are extracted from the reports generated by PMD and other tools.

Each analysis tool requires some custom coding to get the data point.

Those data points are accumulated into a .csv file for the report by

1. Downloading the old CSV file (if there is one) fro mthe project website.2. Adding the new data point as a new line at the end of the CSV file.

3. When the website is uploaded, it will include the new, one-line-longer, CSV file,

These steps are carried out by my own Report Accumulator Gradle plugin.

6.3 Report AccumulatorBack to build.gradle to load another plugin:

build.gradle.listing +

buildscript { repositories { ⋮ ivy { // for report-accumulator url 'https://www.cs.odu.edu/~zeil/ivyrepo' ➀ } } dependencies { ⋮ classpath 'edu.odu.cs.zeil:report_accumulator:1.2' ⋮ } } ⋮ // Reporting

Page 543: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

import edu.odu.cs.zeil.report_accumulator.ReportStats ➁ import edu.odu.cs.zeil.report_accumulator.ReportsDeploy task collectStats (type: ReportStats, dependsOn: ['build','reports']) { ➂ description "Collect statistics from various reports & analysis tools" reportsURL = 'https://www.cs.odu.edu/~zeil/gitlab/' + project.name + '/reports' } task site (dependsOn: ['copyBake', 'copyJDocs', 'collectStats']){ ➃ description "Build the project website (in build/reports)" group "reporting" } task deployReports (type: ReportsDeploy, dependsOn: 'site') { ➄ description 'Deploy website to remote server' group 'reporting' deployDestination = 'rsync://[email protected]:codeCompCommon/reports/' }

1. The usual steps to include a plugin.2. Import the new task types created by the plugin3. A ReportStats task

scans the build/reports directory for reports from various tools,extracts a new data point where it can,downloads an existing CSV file for that report from the reportsURLadds the new data point to the end of the CSV file

4. A slight tweak to our earlier site target to make sure that the ReportStats task is performed

5. A ReportsDeploy task uploads the build/reports directory to the deployDestination URL.Assumes that any required ssh keys are already in an agent.

7 Related ideasContinuous deployment publishes snapshots of deliverables as changes are checked in.

A variation of the rather common “daily build” practice seen on many projects.Some Maven repositories (including our own Artifactory instance) provide separate “snapshot” repositories for this purpose.The idea of “artifacts”, seen earlier, is one way to carry this out.

Page 544: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

GitHub and later versions of GitLab now use the artifacts mechanism to deploy entire project websites, making it unnecessary to work with aseparate web server.

Some organizations actually wire up build light indicators to provide a highly visible indicator of the status of the latest integration build.

Some then point a webcam at the light and broadcast their status.Others opt for publishing a software analog of such lights on their project website.

Page 545: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Lab: Continuous IntegrationSteven J Zeil

Last modified: Apr 8, 2020

Contents:1 Setting up CI2 Deploying Artifacts3 Deploying Reports

This is a self-assessment activity to give you practice in working with the gitlab-ci continuous integration system. Feel free to share your problems,experiences, and choices in the Forum.

1 Setting up CIIn a previous assignment, you set up a project on GitLab with an automated build and some unit tests, all controlled by gradle. We’ll use that as the startingpoint for this lab.

Running continuous integration on gitlab-ci requires a gitlab project with

an automated build,

a designated runner machine/process to execute that build, and

a configuration script, .gitlab-ci.yml that tells the runner what to do to run your build.

1. Make sure that you have a fresh copy of your GitLab1 project from GitLab, and that it builds successfully using the Gradle wrapper.

2. Visit your GitLab1 project on GitLab. Go to the “Settings” page, then select “CI/CD”.

3. Expand “General Pipelines”. Set the Timeout to “5 minutes”, so that a “stuck” or looping build will terminate after a few minutes.

4. Scroll down to “Runners” and expand it.

On this page, you can see runners that are available (“shared”) for general use or that have been registered to work specifically for this project. A specificrunner requires installing special software on a machine that can function as a server and is available whenever you are likely to be committing changes toyour project. Since not everyone may be in a position to set something like that up, we will used a shared runner instead.

Page 546: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The shared runners are identified by various tags, which you will see listed under each one. In your project work, you have been assigned to a teamidentified by a color and a number. For this lab, use the runner matching your team name, e.g., “red1”, “green4”, “blue2”, etc.

5. Return to your local copy of your project. Find the root directory of your project.

If you followed the guidelines for project directory structure carefully, the root directory of your project contains a README file, a .git directorycontaining your git repository, and a sub-directory with your build files and your src/ directory.

If so, your Eclipse project should actually be pointing at that sub-directory. You might find it useful to create a second Eclipse project, GitLab1-root, this one a “General Project” instead of a Java or Gradle project, pointed at the true root directory. This will make it easier to edit files in yourroot directory.

If you were a bit more loose in your structuring, your project’s root directory may have your build files and your src directory in the same directoryas your README and .git repo.

6. In that root directory, create a .gitlab-ci.yml text file. The overall structure of this file should be

stages: - build build-job: tags: - # runner tag name stage: build script: - # script line 1 - # script line 2 - # ... only: - master

In the tags area, insert the identifying tag of the shared runner you selected earlier.

In the script area, you replace the # lines with shell script statements to actually run your build. Typically, this should be short and simple, because all ofthe complicated stuff is already set up to be handled by your build manager.

The script will be started in your project root directory, so if your build files and src directory are actually in a sub-directory, you may want to cdinto that sub-directory.

After that, something like ./gradlew build should actually run your build.

Here is a suggested starting script, liberally sprinkled with ls commands so that you will be able to see what was going on:

script: - ls

Page 547: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

- cd relativePaths - ls - chmod +x gradlew - ./gradlew build - ls build/*

7. When you have finished editing that file, commit your changes and push it to your GitLab project.

8. On GitLab, go to your Repository -> Commits page and you should see your new commit. On the right, you may see a checkmark or other symbolindicating that a build was attempted for this commit.

On your Repository -> Files page you should see your new .gitlab-ci.yml file.

9. Go to your CI/CD -> Pipelines page. You should see a line indicating that a “build” has been added. Depending on how quickly you got here, it mayhave a status of “Pending”, “Running”, “Passed”, or “Failed”.

If you don’t see a build listed, you probably have either failed to commit a .gitlab-ci.yml file to your root directory. Go back and check your Files listingcarefully. If that looks OK, check to be sure that you really did assign a runner to your project.

1. Click on the status symbol to be taken to a listing of what has happened or, if it is running, is currently happened with your running build. If it’s stillrunning, you can watch it in more-or-less real time.

2. If your build failed, try to figure out why and fix it. Common issues include:

Errors in the script portion of the .gitlab-ci.yml file.

Look particularly at whether you have cd’d to the wrong place.

Errors in your build file. Do your builds actually work when invoked from the command line?

A common mistake is to embed absolute paths to libraries and other files within your build instructions. Those paths are specific to your ownmachine and will likely not match anything on the runner machine.

Missing files in your repository. You may have files in your local copy of your project that have not been getting committed to your git repository.Compare your local project listing carefully against the Files page of your project on GitLab. Make sure that your all of your build files (includingthe gradlew wrappers), your source code, and, if you have any, test data input files are being uploaded to the repository.

The build runs as expected, but stops/fails because your code fails one or more unit tests.

When running builds manually, it’s common to stop if any tests fail.

When running in a continuous integration setting, we often want to continue on and collect statistics and reports for the project website.

You can tell your Gradle build to keep going even if some unit tests fail by adding

Page 548: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

test { ignoreFailures = true }

to your build.gradle file.

2 Deploying Artifacts“Artifacts” are the intended final products of a build. For a java project, the artifacts are generally jar files.

When we studied configuration management we saw that projects often deploy their “milestone” releases to large distributed repositories such as MavenCentral, JCenter, or the various Linux distribution repositories.

You may have encountered some projects, however, that have less official releases, e.g., “daily builds”. Continuous deployment is the practice of providing acopy of the project artifacts as a side effect of the continuous integration build.

Examine the build directory for your project. You should find that a Jar file has been created in build/libs/. When your build is done on the gitlab-cirunner, that same file is built, but then sits un the runner, unavailable to anyone. We’re going to set that up to be released on each build of your project.

1. If you don’t have one, add a README.txt or README.md file to your project.

2. Then edit your .gitlab-ci.yml file to add an “artifacts” section:

build-job: tags: ⋮ only: - master artifacts: paths: - path-to-your-README - path-to-your-Jar-file

The paths that you add should be relative paths starting from your project root directory.

3. Commit your changes.

Your project should build on the runner as before. When it is done, however, you should find a download button/link as shown on theright has been to your project’s home page. That provides access to a .zip archive holding the two files we named as artifacts.

Page 549: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

4. Try downloading that file and unpacking it. You can see that the original directory structure separating the two files is preserved.

Something to think about: suppose you wanted to have both files in the top level of the .zip instead of buried in a directory. How could you do that?

3 Deploying ReportsExamine your project again. in build/reports/tests/, you should find a nice little collection of files providing a web-ready summary of your unit testperformance. Suppose that we wanted to put that up on a project website?

The artifact mechanism doesn’t help here, because it would bury the web pages inside a .zip file, and you can’t browse to the interior of an archive.

There is a gradle-ssh-plugin that can be used to copy files. It would be a tad cumbersome to copy the files to the web server one at a time, but we could add acommand to our .gitlab-ci.yml script to zip up the whole report, then use the gradle-ssh-plugin to copy that zip file to our web server, then use it again toissue an unzip command remotely to that web server.

Of course, to use ssh we need to supply a login and password for the remote machine. And we don’t want to put that kind of into our repository where anyonemight read it.

gitLab has a mechanism of “secret variables” that we could use to store a login name and password. We would need to be careful how we make use of thosevariables, to make sure that they don’t have their values listed in the build transcripts where anyone could read them, but it’s definitely possible.

Secret variables can only be examined by the “master” of a GitLab project. But what if a project has more than one “master”? We can improve on this a bit.Remember those command-limited ssh keys you created a long time ago to allow files to be uploaded to your website?

1. In the Settings -> CI/CD area of your GitLab project, go to Variables.

Create a new variable named RSYNC_KEY and, for the value, insert the private key that you created for this purpose.

2. Edit your .gitLab-ci.yml file. We’re going to augment the script for the build-job:

build-job: ⋮ script: ⋮ - eval $(ssh-agent -t 5m -s) - ssh-add <(echo "$RSYNC_KEY") - rsync -auvz -e "ssh" build/reports/tests/ [email protected]:GitLab1/ - ssh-agent -k

making an appropriate substitution for the tags and for yourLoginName.

In the script area,

Page 550: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The first line starts an ssh agent.

The “-t 5m” means that, after you add a key, it will continue to offer that key for up to 5 minutes, which should be more than enough time for whatwe are going to do.

The second line registers the private key stored in your RSYNC_KEY secret variable with that agent.

The third line should use that key to publish your test report to your website.

The final line shuts down your ssh agent. Otherwise the process tends to hang around forever.

3. Commit your changes. Examine the pipeline listing to see if your build completes successfully. If not, try to fix it.

4. Use your web browser to visit https://www.cs.odu.edu/~yourLoginName/cs350/sshAsst/GitLab1/.`

Can you find your test reports?

Something to try: Modify your gradle invocation to build javadocs:

./gradlew build javadoc

Can you modify your .gitlab-ci.yml script to publish those to your website as well? (Hints: you could add a second rsync command, or add acommand to copy the javadoc report into build/reports and modify your rsync command to publish the entire reports directory.)

Page 551: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

System TestingSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Integration and system testing

1.1 Unit to Integration1.2 Integration to System

2 Testing Phases and the Build Manager2.1 How often should we run integration/system tests?2.2 Separating the Tests2.3 Building the Tests

3 Test Coverage3.1 Coverage Measures3.2 C/C++ - gcov3.3 Java

4 Oracles4.1 expect4.2 *Unit4.3 Testing GUI systems4.4 Web systems4.5 Selenium

Abstract

System testing adds particular challenges to testing because it is constrained to work with the actual system inputs and outputs. Compared to unit testing, wehave less control over both the input supply and the capture and evaluation of the output.

In this lesson we look at tools for measuring quality of system testing. We will explore the difficulties that arise when dealing with non-text input and output,particularly graphical interfaces, and will look at some of the support available for testing at this level.

1 Integration and system testingexercise larger potions of code than does unit testing.validates the interactions between separate code features.

Page 552: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1.1 Unit to IntegrationStart with your unit tests.

Replace stubs and mocks by real code.Now they are integration tests!

More to the point, the problem is usually not converting from unit tests to integration tests. As we saw when looking at stubs & mocking, it’s oftencommon to come up with integration tests that we have to work hard at to turn into properly isolated unit tests.

So those “first drafts” at unit tests can often be saved to serve as integration tests.

Supplement with tests of “interesting” interactions among modules.

1.2 Integration to SystemSystem testing is the limiting case of integration testing.

Works with entire program’s inputs and outputs

A challenge when inputs and outputs involve GUIs, databases, and other non-text, non-API components.

Generally fewer tests than under unit and integration testing.

But may run a lot longer

2 Testing Phases and the Build ManagerGenerally, unit tests should run quickly (a matter of seconds)

So we design the build to re-run these every time the code is recompiled.

Integration tests and systems tests may take considerably longer.

Might only want to rerun these during more occasional “reporting” runs when we want a full report on the overall state of the project.

Suggests distinct targets in the build manager.Probably easiest if we keep the different kinds of tests in separate directories

Page 553: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.1 How often should we run integration/system tests?Plausible answers:

Once daily.When we push a set of local changes to the central repository.When merging changes into the master branch.

These kinds of runs are often triggered automatically.

Daily runs cane be a simple timed script.Runs triggered by repository actions are triggered using continuous integration.

2.2 Separating the TestsFor Java projects, we already have a separation of code into src/main and src/test. We might consider adding src/integrationTest and src/systemTest.

I sometimes use src/itest and src/systest.

Each test directory ty[ically has source code (e.g., src/itest/java) and maybe data files (e.g., src/systest/data).

2.3 Building the TestsIn Gradle, we can add test directories with the TestsSets plugin.

In build.gradle:

plugins { id 'java' } repositories { jcenter() } dependencies { testImplementation("junit:junit:4.12") testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.5.2") } test { useJUnit()

Page 554: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

} // Add integration test directory itest sourceSets { iTest { compileClasspath += sourceSets.main.output runtimeClasspath += sourceSets.main.output } } configurations { iTestImplementation.extendsFrom implementation iTestRuntimeOnly.extendsFrom runtimeOnly } dependencies { iTestImplementation 'junit:junit:4.12' }

This adds to a Java project new tasks to compile and run tests from src/iTest/java.

You can configure these tasks independently, e.g.,

iTest.mustRunAfter test ➀ iTest { ignoreFailures = true ➁ } test { ignoreFailures = false ➂ }

➀ Makes sense to run the integration tests only after the normal unit tests.

➁ If we want to generate reports of how many tests passed and failed, we probably need to make sure the build keeps going (so that we can get to thereporting tasks) even if some tests fail.

Keep in mind also that our integration tests are likely to start as things that fail, and will continue to fail until we actually get far enough in the projectdevelopment for losts of the missing pieces to have been finally implemented.

➂ This is for the purpose of illustration only. I don’t know why you would want to kill your reporting after unit test failures. After all, in TDD, we expectsuch failures to be common and to persist for some time.

3 Test Coverage

Page 555: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Although we can monitor test coverage during unit test, it’s more common to do this during integration and system test.

During Unit test, we are working with a lot of “fake” code (drivers and stubs/mocks).

We certainly don’t care how well our drivers and stubs were covered!

Integration and system testing gets to more realistic ’combinations" of operations.

3.1 Coverage MeasuresWe have previously reviewed:

Black-Box Testing

Equivalence partitioningBoundary-value testingSpecial-values testing

White-Box Testing

Structural Testing (a.k.a., “path testing”

Statement CoverageBranch CoverageCyclomatic coverage (“independent path testing”)Data-flow Coverage

Mutation testing

3.2 C/C++ - gcovMonitoring Statement Coverage with gcov

coverage tool includes with the GNU compiler suite (gcc, g++, etc.)

As an example, look at testing the three search functions in

arrayUtils.h +

#ifndef ARRAYUTILS_H#define ARRAYUTILS_H

Page 556: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

// Add to the end// - Assumes that we have a separate integer (size) indicating how// many elements are in the array// - and that the "true" size of the array is at least one larger // than the current value of that countertemplate <typename T> void addToEnd (T* array, int& size, T value) { array[size] = value; ++size; } // Add value into array[index], shifting all elements already in positions// index..size-1 up one, to make room.// - Assumes that we have a separate integer (size) indicating how// many elements are in the array// - and that the "true" size of the array is at least one larger // than the current value of that counter template <typename T> void addElement (T* array, int& size, int index, T value) { // Make room for the insertion int toBeMoved = size - 1; while (toBeMoved >= index) { array[toBeMoved+1] = array[toBeMoved]; --toBeMoved; } // Insert the new value array[index] = value; ++size; } // Assume the elements of the array are already in order// Find the position where value could be added to keep// everything in order, and insert it there.// Return the position where it was inserted// - Assumes that we have a separate integer (size) indicating how// many elements are in the array// - and that the "true" size of the array is at least one larger // than the current value of that counter template <typename T> int addInOrder (T* array, int& size, T value)

Page 557: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

{ // Make room for the insertion int toBeMoved = size - 1; while (toBeMoved >= 0 && value < array[toBeMoved]) { array[toBeMoved+1] = array[toBeMoved]; --toBeMoved; } // Insert the new value array[toBeMoved+1] = value; ++size; return toBeMoved+1; } // Search an array for a given value, returning the index where // found or -1 if not found.template <typename T> int seqSearch(const T list[], int listLength, T searchItem) { int loc; for (loc = 0; loc < listLength; loc++) if (list[loc] == searchItem) return loc; return -1; } // Search an ordered array for a given value, returning the index where // found or -1 if not found.template <typename T> int seqOrderedSearch(const T list[], int listLength, T searchItem) { int loc = 0; while (loc < listLength && list[loc] < searchItem) { ++loc; } if (loc < listLength && list[loc] == searchItem) return loc; else return -1; } // Removes an element from the indicated position in the array, moving// all elements in higher positions down one to fill in the gap.template <typename T>

Page 558: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

void removeElement (T* array, int& size, int index) { int toBeMoved = index + 1; while (toBeMoved < size) { array[toBeMoved] = array[toBeMoved+1]; ++toBeMoved; } --size; } // Search an ordered array for a given value, returning the index where // found or -1 if not found.template <typename T> int binarySearch(const T list[], int listLength, T searchItem) { int first = 0; int last = listLength - 1; int mid; bool found = false; while (first <= last && !found) { mid = (first + last) / 2; if (list[mid] == searchItem) found = true; else if (searchItem < list[mid]) last = mid - 1; else first = mid + 1; } if (found) return mid; else return -1; } #endif

with test driver

Page 559: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

gcovDemo.cpp +

#include <cassert>#include <iostream>#include <sstream>#include <string> #include "arrayUtils.h" using namespace std; // Unit test driver for array search functions int main(int argc, char** argv) { // Repeatedly reads tests from cin // Each test consists of a line containing one or more words. // The first word is one that we want to search for. The // remaining words are placed into an array and represent the collection // we will search through. string line; getline (cin, line); while (cin) { istringstream in (line); cout << line << endl; string toSearchFor; in >> toSearchFor; int nWords = 0; string words[100]; while (in >> words[nWords]) ++nWords; cout << seqSearch (words, nWords, toSearchFor) << " " << seqOrderedSearch (words, nWords, toSearchFor) << " " << binarySearch (words, nWords, toSearchFor) << endl; getline (cin, line); }

Page 560: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

return 0; }

which reads data from a text stream (e.g., standard in), uses that data to construct arrays, and invokes each function on those arrays, printing the results of each.

Compiling for gcov Statement Coverage

To use gcov, we compile with special options

-fprofile-arcs -ftest-coverage

When the code has been compiled, in addition to the usual files there will be several files with endings like .gcno

These hold data on where the statements and branches in our code are.

Running Tests with gcov

Run your tests normally.

As you test, a *.gcda file will accumulate data on your test coverage.

Viewing Your Report

Run: gcov_mainProgram_The immediate output will be a report on the percentages of statements covered in each source code file.Also creates a *.gcov detailed report for each source code file. e.g.,

Sample Statement Coverage Report

-: 69:template <typename T> -: 70:int seqSearch(const T list[], int listLength, T searchItem) -: 71:{ 1: 72: int loc; -: 73: 2: 74: for (loc = 0; loc < listLength; loc++) 2: 75: if (list[loc] == searchItem) 1: 76: return loc; -: 77: #####: 78: return -1; -: 79:}

Page 561: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Report lists number of times each statement has been executedLists #### if a statement has never been executed

Monitoring Branch Coverage with gcov

gcov can report on branches taken.

Just add options to the gcov command:gcov -b -c_mainProgram_

Reading gcov Branch Info

gcov reportsNumber of times each function call successfully returnedNumber of times a branch was executed (i.e,, how many times the branch condition was evaluated)

and number of times each branch was taken

For branch coverage, this is the relevant figure

But What is a “Branch”?

A “branch” is anything that causes the code to not continue on in straight-line fashion

Branch listed right after an “if” is the “branch” that jumps around the “then” part to go to the “else” part.&& and || operators introduce their own branchesOther branches may be hidden

Contributed by calls to inline functionsOr just a branch generated by the compiler’s code generator

In practice, this can be very hard to interpret

Example: gcov Branch Coverage report

-: 84:template <typename T> -: 85:int seqOrderedSearch(const T list[], int listLength, T searchItem) -: 86:{ 1: 87: int loc = 0; -: 88: 1: 89: while (loc < listLength && list[loc] < searchItem)

Page 562: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

branch 0 taken 0 call 1 returns 1 branch 2 taken 0 branch 3 taken 1 -: 90: { #####: 91: ++loc; branch 0 never executed -: 92: } 1: 93: if (loc < listLength && list[loc] == searchItem) branch 0 taken 0 call 1 returns 1 branch 2 taken 0 1: 94: return loc; branch 0 taken 1 -: 95: else #####: 96: return -1; -: 97:}

Report is organized by basic blocks, straight-line sequences of code terminated by a branch or a call

Hard to map to specific source code constructs

lowest-numbered branch is often the leftmost conditionFact of life that compilers insert branches and calls that are often invisible to us

3.3 JavaJava Coverage Tools

Clover

JaCoCo

Part of the EclEmma project (Eclipse plugin for Emma)Emma, an older coverage tool, now replaced by JaCoCo

Clover

Commercial product, currently free for open-source projects

integrates with Ant, Mavenlots of reporting features

Page 563: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Works in “traditional” coverage tool fashion

Requires a “fork” of the build process to build a monitoring versionInjects monitors into compiled code

Test optimization: can re-run only those tests that covered changed code

JaCoCo

Java Code Coverage

line and branch coverage

Instrumentation is done on the fly

An “agent” monitors execution of normally compiled bytecodeNo special build required

Works with Eclipse

JaCoCo “started” as an Eclipse plug-in

Works with Maven & Ant

In Ant, wrap normal <java> and <junit> tasks inside a <jacoco:coverage> element

Works with Gradle

Just apply the plug-in.

Example: JaCoCo in Eclipse

Using JaCoCo in Eclipse

Once you have the plugin installed,

1. Open any Eclipse Java project.2. Right-click on a unit test or executable. Look for “Coverage As”

Function of this is the same as “Run As” and “Debug As”, but monitors coverage during execution.

3. After execution has completed coverage results are shown

Page 564: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A summary in the console area under the “Coverage” tabDetails in the Java editor, as color coding

Green means that all branches were coveredRed means that none were covered.Yellow means that some were covered.

Page 565: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Example: JaCoCo in Gradle

In build.gradle:

plugins { id 'java' id 'jacoco' } ⋮ check.dependsOn jacocoTestReport

The last line is because I typically have a task named “check” that is my target for report generation. In other words, I plan to use

./gradlew check

to prepare all of my project reports, so I add a dependency between each kind of report I add and the check task.

Example: JaCoCo Report

Report

4 OraclesA testing oracle is the process, person, and/or program that determines if test output is correct

4.1 expectCovered previously, expect is a shell for testing interactive programs.

an extension of TCL (a portable shell script).

Page 566: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Largely confined to text streams as input/output

4.2 *UnitCan we use *Unit-style frameworks as oracles at the system test level?

The very question is heresy to many *Unit advocates

Particularly runs counter to the goals of the various Mock Objects projects

But, why not?

Such tests do not (should not) be at the expense of having done earlier “proper” unit testing.

Particularly in Java, MyClass.main(String[]) can be called just like any other function

And System.in (cin) and System.out (cout) can be rerouted to/from files or internal strings

Major limitation is the accessibility of system inputs & outputs.

GUIs, data bases, etc.

4.3 Testing GUI systemsScripting or record/playback: playing back input events for

convenience & efficiencyconsistent reproducibility

Capture of results

Can occur at different levelsevent/message levelgraphics level

Some Open Alternatives

Marathon - free in limited version

Jemmy

Page 567: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Marathon

For Java GUIs

Recorder captures AWT/swing events as JRuby scripts

Scripts can then be edited to alter inputs, add assertions, etc.

def test $java_recorded_version = "1.6.0_24" with_window("Simple Widgets") { select("First Name", "Jalian Systems") select("Password", "Secret") assert_p("First Name", "Text", "Jalian Systems") } end

Jemmy

Also for Java GUIs

Tests scripted as Java

Integrates with JUnit

Example

4.4 Web systemsA subproblem of GUI testing

Simpler because input structure more constrainedOutput detail level is fixed (http: events)

Some Open Alternatives

Selenium

antEater

Page 568: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Watir

4.5 SeleniumBrowser automation (SeleniumIDE - Firefox add-on)

Record & playbackOr scripted (Selenium Webdriver)

Firefox, IE, Safari, Opera, Chrome

Selenium Scripting

Actions do things to elements.

E.g., click buttons, select options

Accessors examine the application state

Assertions validate the state

Each assertion has 3 modes

assert: failure aborts the testverify: test continues, but failure is loggedwaitFor: conditions that may be true immediately or may become true within a specified time interval

Selenese

A typical scripting statement has the form

command parameter1 [parameter2]

Parameters can be

locators for finding a UI element within a page (xpath)

text patterns

variable names

Page 569: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

A Sample Selenium Script

<table> <tr><td>open</td><td>http://mySite.com/downloads/</td><td></td></tr> <tr><td>assertTitle</td><td></td><td>Downloads</td></tr> <tr><td>verifyText</td><td>//h2</td><td>Terms and Conditions</td></tr> <tr><td>clickAndWait</td><td>//input[@value="I agree"]</td><td></td></tr> <tr><td>assertTitle</td><td></td><td>Product Selection</td></tr></table>

That’s right – it’s an HTML table:

open http://mySite.com/downloads/assertTitle DownloadsverifyText //h2 Terms and ConditionsclickAndWait //input[@value=“I agree”]assertTitle Product Selection

A Selenium “test suite” is a web page with a table of links to web pages with test cases.

Selenium Webdriver

An alternate version of Selenium is more code-oriented. It provides APIs to a variety of languages allowing for very similar capabilities:

Select select = new Select(driver.findElement( By.tagName("select"))); select.deselectAll(); select.selectByVisibleText("Edam");

Selenium works by interacting with a “real” web browser (Firefox, Chrome) to simulate actions like clicking on or sending keystrokes to a web page element.

I’ve used Selenium Webdriver to implement some very nice web scraper applications.

Waiting

A tricky thing about testing web applications is the unknwon amount of time that may be required to respond to a click or other interaction.

Valid tests often need to give very specific instructions to wait for pages to be loaded and for elements to become visible and clickable.

Page 570: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

WebDriver driver = new FirefoxDriver(); driver.get("http://somedomain/url_that_delays_loading"); WebElement myDynamicElement = ( new WebDriverWait(driver, 10)) .until(ExpectedConditions.elementIsClickable( By.id("myDynamicElement")));

Waits up to 10 seconds for an expected element to load and become active.

Page 571: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Regression TestingSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Regression Frameworks

1.1 DejaGnu1.2 fitnesse

2 Maveryx

Abstract

Regression testing monitors the changes, for better or worse, of the system as we make changes to it. Regression testing generally involves large numbers oftests, often selected as a mixture of test cases originally developed as unit, integration, and system tests.

In this lesson we will look at what is required for support of regression testing.

1 Regression FrameworksWhat Makes a Testing Framework a Regression Framework?

Little agreement, but IMNSHO

System-level orientation

Technically, regression tests can come from any level of normal testing

High degree of automation

Regression sets can be huge

Allowance for both expected pass and expected failure cases

Regression testing is about learning what has changed, not what has passed

Page 572: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Open Possibilities

DejaGNU

fitnesse

Maveryx

1.1 DejaGnuPosix-compliant regression test framework

Written in expect

Strong support for multiple configurations

Test Results

Standard for test frameworks.

Possible outputs for any test:

PASS: test has succeeded

FAIL: test has failed

XFAIL: test has failed, but the failure was expected

XPASS: test has passed, but was expected to fail

UNRESOLVED: The test has produced indeterminate results and requires human review for resolution

UNTESTED: The test was not run.

This is a placeholder for tests that have not yet been written.

UNSUPPORTED: The test cannot be run because of external conditions

(e.g., it is OS-specific and we are testing in a different OS).

Sample Test

Page 573: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

set testdata { {"addition" "22 + 1" "23"} {"multiplication" "21 * 2" "42"} {"division" "14 / 3" "4"} ⋮ } foreach pattern $testdata { eval "spawn ./calc [lindex $pattern 1]" expect { -re [lindex $pattern 2] { pass [lindex $pattern 0] } default {fail [lindex $pattern 0] } } }

Running DejaGnu

runtests --tool calcTests

runs all tests in the calcTests directory, producing output like:

PASS addition PASS multiplication ⋮ # of expected passes 12 # of unexpected failures 2

1.2 fitnesseTests composed on Wiki pages

Encourages collaborative dvelopment & readable documentation

Tool walks pages to run tests

example

Is fitnesse a Regression Framework?

Page 574: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Advertises itself as such.

Not clear to me how to extend it past simple text I/O

Is this really a system-level approach?

Concept of expected fail is missing

2 MaveryxJava & Android GUI testing

Traditional GUI element searching replaced by “object recognition” expertsIs this really different from programmed searches?Features some “fuzzy” search criteria

Scripting in Java

Use JUnit 4 assertions to write your oracle code.

Is Maveryx a Regression Framework?

Advertises itself as such.

Appears to have legitimate system-level focus

Expected fail?

Page 575: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Issue TrackingSteven J Zeil

Last modified: Dec 21, 2019

Contents:1 Issue Tracking

1.1 Basic Questions2 Bugzilla3 Other Systems4 Eclipse - Mylyn

Abstract

Issue Tracking has long been recognized as an essential part of software maintenance.

In this lesson we will look at the kinds of information managed in typical issue tracking systems, and will discuss some of the ways in which an issue trackingsystem can impact even pre-maintenance development activities.

1 Issue TrackingAn apparently mundane task with significant impact on

maintenance cost

customer satisfaction

project personnel management

1.1 Basic QuestionsRoles in an Issue Tracking System

Users (internal or external to the project team) report problems

Project administrators prioritize problems and assign some to project staff

Page 576: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Project staff report on status of problem solution

What Questions Does an Issue Tracking System Answer??

What problems are currently open?

Is anyone working on these problems?What’s their status?

Which of those are the most severe?

Have similar problems been reported in the past?

What is tracked?

Which release(s) does the problem occur in?

What are the environmental factors?

Operating system3rd party software

Problem history

Can the problem be reproduced? How?

Expected behavior

Observed behavior

Open Alternatives

Bugzilla was one the earliest well-known such systems

Defined much of the feature set and organization still used by its successors

Commonly integrated into Forges to take advantage of infrastructure already provided for project management

particularly personnel mgmt.

Page 577: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2 BugzillaOriginally for Mozilla/Netscape project (1998)

Major updates have continued through 2011 (v4.0)

Bugzilla Problem Report

Page 578: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance
Page 579: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Bugzilla Classifies Problems by

Severity

Blocker (a.k.a Showstopper): blocks development or testingCritical: crashes, loss of dataMajor: loss of important functionalityNormalMinor: minor functionality loss and/or a workaround is availableTrivial: e.g., misspelled messagesEnhancement: request for new features

Priority

Numeric, assigned by project managers

Bugzilla also Tracks

Comments (forum-style)

Notifications desired

The Life-Cycle of a Problem

Page 580: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

What Goes into the System?

Problems can be reported by end-users or team members

Team members will generally not enter simple test failures

“Test cases make problems reports obsolete”Unless the fix is outside their personal area of responsibility or they want someone else to step in

Page 581: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Team members may use to track ideas and feature requests

3 Other SystemsForges

Most forge systems integrate some form of issue tracking

Already provide personnel management

E.g., FusionForge provides separate tracking of bug reports and feature requests

Provides for attachment of files (test cases)Assignment of a report to a project member generates a task in that person’s to-do listCan track scm commits that fix problem via Tracker links on SCM pages

Compare to our own Gitlab

Other Possibilities

Search capabilities vary widely

Some systems link problem reports to regression tests

More general project task managers exist

E.g., Agile developers allocate “stories”

4 Eclipse - MylynPersonal & shared task manager for Eclipse

Generally included with most programming language support packages

Mylyn supports two kinds of tasks

Local tasks, stored in the Eclipse workspaceShared tasks, from an issue tracking system or project task manager

e.g., Bugzilla, github, FusionForge

Page 582: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Mylyn distinguishes between due dates and schedule dates

Task management with Mylyn

MyLyn and Project Perspectives

Page 583: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. personal task list, including Bugzilla reports

2. Change set related to task

3. Task editor

4. Context-based task info

Working with an Issue-Tracking System

Add a connector to the issue trackerGitLab connector at Eclipse update site http://pweingardt.github.com/mylyn-gitlab

Define one or more queries indicting what issue reports you want to be displayed by mylyn

E.g., in OurProject, display all reports assigned to me as tasks

Select a task to update info (will synchronize with remote manager)

Or create new tasks

Task List

Can display by category/query or by date

Searching & filtering are possible“Focus on work week” option

Color changes indicate scheduling & status

Page 584: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

red for overdue tasksblue for tasks scheduled for todayblack for tasks scheduled for later in the weekgreen for tasks completed todaygrey for tasks completed earlier

Context Management

The context of a task is the collection of files & information related to the task.

E.g., Java files related to a bugChanges made in the course of fixing it

When you activate a task, Eclipse/Mylyn tracks the context

The Focus on Active Task button causes the package explorer to show only elements in the active task’s context

Establishing Context

From the task list, activate a task.

The package explorer switches to “Focus on Active Task” modeIf you are starting work on this task, this is empty

Clear by releasing the Focus on Active Task button or alt-clicking to expand an element in the explorer tree.

Start working

As you open files directly from the package manager, or indirectly (e.g., using Show Declaration (F3), Open Type (Ctrl-Shift-T), or ShowReferences (Ctrl-Shift-G), they are added to the focused package manager view.

Restoring Context

You can deactivate the currently active task (or activate a different task that you want to switch to).

Your various open editor windows close and the package manager returns to its normal unfocused state

You “return” to a task by re-activating it.

Your editor windows for that task context are restored

Page 585: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Contexts and Tests

You can create a Context Test Suite of those JUnit tests that you will be frequently re-running as you work on your active task.

Contexts and Change Sets

Changes made while working on an activated tasks are checked

Change sets can be manipulated in the synchronize viewCVS & SubversionSaid to work with Egit, but I’m not seeing it in practice

Machine Hopping

A major limitation (IMO) of the Mylyn context support is its limitation to a single workspace

I frequently work on the same project on different machines (office and home)

Things I have yet to try

Exporting and importing of tasksNot clear if context is included

Changing the task list data directory to a dropbox folder

Page 586: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Agile MethodsSteven J Zeil:

Last modified: Dec 21, 2019

Contents:1 Agile as a Social Entity

1.1 Agile Development is1.2 Variations

2 Common Practices of Agile Development2.1 Fundamentals2.2 Common Intersections

Abstract

Agile methods are a modern approach to incremental development.

They emphasze:

Iterative & incremental developmentFrequent communication with customer representativesShort “time-boxed” development cyclesFocus on quality as a matter of professional pride

This lesson is a discussion of the origins of Agile Development and a quick overview of the basic principles.

1 Agile as a Social Entity1.1 Agile Development is

A reaction against heavily-managed, documentation-heavy processesA social movement within the software development profession

Introduced in the Agile Manifesto (2001)

1.1.1 The Agile Manifesto

Page 587: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

We are uncovering better ways of developing software by doing it and helping others do it. Through this work we have come to value:

Individuals and interactions over processes and toolsWorking software over comprehensive documentationCustomer collaboration over contract negotiationResponding to change over following a plan

That is, while there is value in the items on the right, we value the items on the left more.

1.1.2 The Twelve Principles of Agile Software

1) Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.

2) Welcome changing requirements, even late in development. Agile processes harness change for the customer’s competitive advantage.

3) Deliver working software frequently, from a couple of weeks to a couple of months, with a preference to the shorter timescale.

4) Business people and developers must work together daily throughout the project.

5) Build projects around motivated individuals. Give them the environment and support they need, and trust them to get the job done.

6) The most efficient and effective method of conveying information to and within a development team is face-to-face conversation.

7) Working software is the primary measure of progress.

8) Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely.

9) Continuous attention to technical excellence and good design enhances agility.

10) Simplicity – the art of maximizing the amount of work not done – is essential.

11) The best architectures, requirements, and designs emerge from self-organizing teams.

12) At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.

1.2 VariationsExtreme programmingScrum

Page 588: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2 Common Practices of Agile Development

source: The Agile Alliance

Page 589: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.1 Fundamentals

2.1.1 User stories

Key idea in all agile variations.

A user story is a mechanism for incremental requirements elicitation and analysis.

Stories are not Requirements

…despite the focus on functionality and non-functional characteristics.

Stories are “a promissory note for a future conversation” (Cockburn)A use-case is a transcript of that conversation (Standley)

Stories are a way of prioritizing workIncluding the work of eliciting detailed requirements

Story Boards

Stories grouped on a story board to help “enrich” the stories

Story boards can be organized in many different waysOur project boards have emphasized TDDMore commonly, related stories are grouped into subtasks that are shown in a common swimlane.

2.1.2 Teams

small groups, largely full-timecontains all required skills (technical and domain expertise)

Stakeholder representative(s) is a regular team member

2.1.3 Iterative development

Activities repeat (analysis, design, testing, …)Work products can be revisited (enhancements, refactoring, etc.)Scheduling may focus on short, repeated development cycles

Page 590: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.1.4 Incremental development

Each successive version of the productis “usable”adds user-visible functionality

Contrast this with a strategy of delivering successive, complete subsystems that will not be revisitedThink of building a house by adding room after room, as opposed to pouring the whole foundation, then framing all the exterior walls, then laying all thefloors, then doing all the electrical wiring, then doing all the plumbing, then…

When can you start using the house?

2.1.5 Version Control

’nuff said

2.2 Common Intersections

2.2.1 Iteration Planning

Teams typically try for 4-10 stories per iteration

Select stories to implement in current implementation

Often organized onto a task board

Velocity

Rate at which functionality (user stories) completed per iteration.

Most agile approaches define a fixed number of days per iteration

Add up the effort estimates of all stories completed during an iteration. This is the team’s current velocity.

Used to estimate time remaining to complete the project

Task Board

Contains stories to be completed in current iteration

Page 591: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Combines story cards and task notes

task notes indicate team member responsiblecolor coding may designate feature, bug, general noteseach task is marked with an estimate of hours required

Task notes organized in columns

To do: tasks yet to be startedIn process: task that team members are working onTo verify: believed completed, needs to be checkedDone: verified as completed. Some boards also list

Backlog: related stories not being handled this iteration

2.2.2 Sustainable pace

Setting a work pace that can be sustained indefinitely

overtime only in critical, unusual, and limited circumstancesSome evidence shows that routine overtime reduces productivity

Once a pace has been established, teams can measure velocity

Page 592: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.2.3 Meetings

Emphasis on co-location of teams to enhance communicationDaily meetings to review key coordination points

time-boxed to very short time periods (e.g., 15 min.)Any topic that starts a discussion is cut short and discussed by interested parties after the meetingThree Questions (Scrum)

1. What have you completed since the last meeting?2. What do you plan to complete by the next meeting?3. What is getting in your way?

Avoid “Yesterday I did X. Today I will continue working on X”the Scrum Zombie patternhelps if user stories define units of work that can be completed in a day

2.2.4 Rules of Simplicity

(Kent Beck)

Each code unit

is verified by automated testscontains no duplicationexpresses separately each distinct idea or responsibilitycontains the minimum number of components compatible with the first 3 rules

2.2.5 TDD

Test-Driven Development goes beyond our previously-cited “test first, code later” rule

1. write a “single” unit test describing an unimplemented functionality2. run the test (it should fail at this stage)3. write “just enough” code to make the test pass4. refactor the code until it conforms to the rules of simplicity

The four steps above are repeated, adding new, tested functionality each time.

2.2.6 Simple Design

Design is on-going

Principles include

Page 593: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

refactoringYAGNI

“You Ain’t Gonna Need It” - argument against early design of elaborate components for future use: “We going to need X eventually. We might waswell design it now.” “YAGNI”

Design should be emergent

good global design will emerge from careful attention to local design questionsWishful thinking?

2.2.7 Familiar Intersections

RefactoringContinuous Integration

Page 594: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Extreme Programming (XP)Steven J Zeil:

Last modified: Dec 21, 2019

Contents:1 Values2 Principles3 Practices

3.1 Teamwork3.2 Energized Work3.3 Planning3.4 Integration3.5 Programming

Abstract

Extreme Programming (Kent Beck, 1999) is an agile approach characterized by

pair programming,test firstshort development cycles (7-10 days) between releases,sustainable paceSearch for simplest increments with no “big design up front”

In this lesson we will explore these component ideas and how they combine into a cohesive development model.

1 ValuesCommunicationSimplicity

“What is the simplest thing that could possibly work?”

Beck notes that many people don’t hear the 2nd half of the question and respond “We can’t possibly make this system simple because…” If it really won’twork, it won’t work. But that’s not the point. There still is a simplest thing that will work.

Page 595: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

“bias your thinking toward eliminating wasted complexity”

Feedback

Understanding what has changed & what we are getting wrongIncludes opinions & observations on what turned out to be complicated, hard to do, hard to get right, etc.

Courage

a bias toward action

Respect

care about the team members

care about he project

2 PrinciplesHumanity: concern for the team members

Economics: Make sure that what you are doing has value to the customer.

Mutual Benefit: “Every activity should benefit all concerned.”

e.g., automated tests help me (the developer) design & code today. Also benefit maintainers down the road. Benefit customers by improvingreliability and reducing costs

negative example: extensive internal documentation

Self-similarity

when you find a pattern (code or work practices) that works, stick with it

Improvement

“In software development, ‘perfect’ is a verb, not an adjective.”

Diversity: skills attitudes, and perspectives

Reflection:

Page 596: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

time is set aside to review how well development is going,informal reflection within team is encouraged

Flow: continuous flow of activities rather than discrete phases

Opportunity (rather than problems)

Redundancy

critical, difficult problems approached many ways

Failure

should not be fearedprototypes and experiments are useless if only employed when we are sure they will succeed

Quality

Quality is not a control variable. Projects don’t go faster by accepting lower quality."

Baby Steps

Organizations can add XP practices incrementally

Accepted Responsibility

“Responsibility cannot be assigned. It can only be accepted.”Whoever signs up to do work also estimates it.The person implementing a story is responsible for design, implementation, and testing.

3 Practices

Page 597: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

(Beck, Extreme Programming Explained, Figure 3)

We’ll focus on the primary ones in the upper half of this diagram.

3.1 Teamwork

Whole Team

Team must span the required skill set for the project

Page 598: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

People need a sense of belonging, of sharedpurpose

Splitting people across projectsdetracts from these

Team size (Gladwell):

12 is the max number of people that caninteract with each other in a day

150 is the limit to recognizing the faces ofeveryone on the team

3.1.1 Sit Together

Open space big enough for whole teamsmall spaces nearby for privacy

3.1.2 Informative Workspace

“An interested observer should be able to walk into the team space and get an idea of how the project is going in fifteen seconds.”Story & task boards“big, visible charts”

3.2 Energized Work

“Work only as many hours as you can beproductive”

“and only as many hours as you can sustain”

3.2.1 Pair Programming

Page 599: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Write all production programs with two people sitting at one machine.

Pairs…

keep each other on taskclarify ideasavoid frustrating “stuck” pointskeep each other accountable for team quality standards

Thinking an be done alone, but not coding

Rotate pairs frequently

e.g., every hour or soEventually, each invidiual should pair with everyone on the team

3.3 Planning

Stories

Units of planning.

“the word ‘requirement’ is just plainwrong. Out of one thousand pages of‘requirements’, if you deploy a systemwith the right 20% or 10% or even 5%,you will likely realize all of the businessbenefit envisioned for the whole system.So what were the other 80%? Not ‘requirements’; they weren’t really mandatory or obligatory.”

Stories lead to earlier estimation than requirementsEncourages team to think in terms of greatest return from smallest investment.

3.3.1 Weekly cycle

Opening meeting

Page 600: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Review progress so farHave customers pick a week’s worth of storiesBreak stories into tasks.

Start week by writing automated tests for the stories

Rest of week is implementation and debugging

At end of week, software is deployable with new functionality

Why a week? Beck suggests that it is a natural unit for teams to work in. Everyone focuses on Friday. It is easy to tell if you have fallen behind and need to re-allocate tasks or stories so that you will have something deployable,

3.3.2 Quarterly Cycle

At the start of a quarter, reflection and planning

Reflection

Planning

identify bottlenecks, especially externaldevise a reaction or workaround

Pick the “themes” for the quarterPick a quarter’s worth of stories to meet that themeInclude some slack: minor stories that can be dropped if you fall behind

Quarterly planning meshes well with traditional business schedules.

“Themes” help refocus team o nthe “big picture”.

3.4 Integration

Ten-Minute Build

Automated build should build and run tests in ten minutes

Anything longer should be done less frequently.

Page 601: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

“A build that takes longer than ten minuteswill be used much less often, missing theopportunity for feedback. A shorter builddoesn’t give you time to drink your coffee.”

3.4.1 Continuous Integration

Integrate and test changes every couple of hours

“Team programming isn’t a divide and conquer problem. It’s a divide, conquer, and integrate problem”

Asynchronous (sometime after checking of changes)Synchronous (on demand by team)

provides an opportunity for reflection

Integration should produce the complete product

3.5 Programming

Test-First Programming

Write a failing test before changing any code.

Addresses:

scope creep: putting in code “just incase”coupling and cohesion: If it’s hard towrite a test, you have a designproblem, not a testing problem.Trust: (team building)

Page 602: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Rhythm

3.5.1 Incremental Design

Create conditions where changes in design do not have exaggerated costs (a la Boehm)

Adapt the design to changes in (or discovery of) requirements

Page 603: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

ScrumSteven J Zeil:

Last modified: Dec 21, 2019

Contents:1 Values2 Practices

2.1 Scrum Teams2.2 Scrum Events2.3 Backlogs

3 Scaling Up

Abstract

An agile approach characterized by

small teams with a few distinct but clearly definedrolesDevelopment cycles through sprints of 7-30 days

Planning meeting at beginningDaily scrum meeting (< 15 min.)Sprint Review meeting at end to review workcompleted (or not)Sprint Retrospective meeting at end to discussprocess

In this lesson we will look at the component activities andstrategies of Scrum We will pay particular attention to theways in which Scrum differs (in practice or in emphasis)from Extreme Programming.

Scrum in Context

Page 604: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

As the name suggests, Scrum

focuses a bit more on the team than onthe toolsenvisions a kind of controlled chaos

1 ValuesTransparency

Process must be visible to those responsible for the outcomeCommon standards contribute to understandability

Examples:

ubiquitous languagedefinition of “Done”

Inspection

Page 605: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Scrum participants inspect one anothers’ work

Contrast with XP’s pair programming

Adaptation

Inspections lead to adjustment of process (not products)

2 Practices2.1 Scrum Teams

Product owner

representative or agent of stakeholdersmanages the project backlog (list of unimplemented work)

Scrum master

interface between project owner and development teamaids project owner in arranging backlogensures that development team adheres to Scrum practicesremoves impediments to team’s progress“facilitates” Scrum events

Development team

3–9 membersmust span required skill setany internal roles are self-organized

2.2 Scrum Events

2.2.1 Sprints

7–30 day, time-boxed iterationsproduces a new product incrementfocused on a Sprint Goal

Page 606: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.2.2 Sprint Planning

Held at beginning of sprint:

What will be delivered in the next increment?Stories selected from project backlogdefines the Sprint Goal

How will the work be done?Work planned for first few days of springDecomposed into tasks.

2.2.3 Daily Scrum

15-minute daily meeting

Each development team member explains

What did I do yesterday?What will I do today?Are there any impediments that will prevent us from reaching the Spring Goal?

2.2.4 Sprint Review

Held at end of sprint4-hour time-boxed meeting (for 1-month sprints)

Product owner

explains what items are Done and not DoneReviews the new state of the project backlog

Development Team

explains what went well and poorlydemonstrates the increment and answers questions

Entire team

discuss what to do nextdiscusses external changes

2.2.5 Sprint Retrospective

Page 607: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

After sprint review, before next sprint planning3-hour time-boxed meeting

Team inspects its own performance

people, relationships, process, toolsIdentifies potential improvementsSets quality goals

adjusting definition of “Done”

2.3 Backlogs

2.3.1 Project Backlog

Unimplemented requirementsoften, but not always stories

2.3.2 Sprint Backlog

Unimplemented tasks that are part of the Sprint GoalManaged on task board

Page 608: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2.3.3 Burndown Charts

A burndown chart shows amount of work remaining in the sprint backlog

updated dailydisplayed in team work area

Page 609: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

provides visual indicator of progress

3 Scaling UpAn extension to Scrum for larger projects:

Scrum of ScrumsEach Daily Scrum appoints one team member to serve as the day’s “ambassador” to a daily Scrum of Scrums meetingSame basic questions as Daily Scrum, adjusted for team level

What has your team done since we last met?What will your team do before we meet again?What impediments (especially those that will affect other teams) does your team foresee?

Page 610: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Project Phase 2: User StoriesCS350

Last modified: Feb 20, 2020

Contents:1 Team Sign-up

1.1 Civility among Team Members2 Group Information3 Project Setup4 Compose Your Stories5 Plan Your Increments6 Peer Evaluation7 Submission8 Evaluation

8.1 Grading of Project Phases8.2 Common Problems with Stories

In this phase of the project, you will prepare user stories for the project and enter them into an issue tracking system. These stories will help to organize yourteam’s work in the later phases.

Your reference materials for this phase include

the requirements definition from the previous phaseyour SRS from the previous phase (depending upon your team membership, you may have more than one to look at).these design notes, which may be particularly useful when you are trying to estimate the effort required to implement your stories.

1 Team Sign-upTeams for this and the remaining phases will be selected by sign-up.

Go to the groups area in your recitation section on Blackboard. Each recitation section has been assigned an arbitrary color, and groups are available with namesconsisting of that color plus a number. Sign up for one of those groups.

All team members must be enrolled in the same recitation date/time.

You should only sign up as the 6th member of a team only if all other teams for that recitation have at least 5 members already.

Page 611: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

After the sign-up due date I will arbitrarily assign students who have not signed up and will shift people out of teams with 5 or 6 members to teams with 3or fewer members. I may merge 2-person teams to create a 4-person team.

I will post an announcement when this has been done.

After signing up for your group, log in to the CS350 GitLab and the CS350 OpenProject tracking board.

This establishes your credentials on each of those systems, which must be done before projects can be set up.

1.1 Civility among Team MembersYou will be working with your team for many weeks, and there will be a lot of communication expected among team members.

In accordance with the Monarch Creed and Code of Ethics, I expect all students to maintain civility in their dealings with one another.

Language that is abusive, harassing, or threatening to members of the class or that fosters high levels of personal and emotional anxiety may, at theinstructor’s discretion, result in expulsion from the team. Given the importance of the team project to this course, that is likely to result in a failinggrade. Egregious or repeated violations will be referred to appropriate authorities for possible disciplinary action.

2 Group InformationWithin 24 hours of my announcement that the groups have been formed, post to your group’s discussion area:

1. Your name.

2. Your CS login name.

3. Your @odu.edu email address.

3 Project SetupOnce 24 hours have passed since my announcement of the groups being formed, the projects can be set up.

1. One team member should create a new project on the OpenProject tracking board and add the other team members to that project (as “Project admin”s).

Note that you cannot add people to a project until they have logged into the tracker for the first time. But they should have done this by now.

Page 612: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

The project name should match the group name from Blackboard, dropping any blank spaces. For example, if your group is “Blue 2”, your projectname should be “Blue2”.

On the New project page for the project, make sure that the project is not public.

This can also be set from the Project settings page after the project has been created.

On the New project page for the project, select/check Backlogs and Work package tracking. I recommend clearing the other modules.

This can also be set from the Project settings page after the project has been created.

Go the the Backlogs page. Use the +Version button to create a new “version” of the project titled “Project Backlog”. For the “start date”, give thecurrent date. For the “Finish date”, give the date of the end of Phase 5 from the course Outline. Status should be “Open”, Sharing “Not shared”, andColumn should be “left”.

2. One team member should also create a new project on Gitlab and add the other team members to that project (as “masters”). The project name must bethe same as on OpenProject – your group name.

Again, this project should be private, not public.

4 Compose Your Stories1. Your project area on Gitlab includes a Wiki. You will use this as the base for your project’s web page. In this phase, you will mainly be documenting your

plans for the first two increments of development, corresponding to phases 3 and 4 of the project.

Set up the opening page (the page that you reach by clicking on the “Wiki” link from your project home page) of your group’s Wiki with three sections.The Membership section should contain a list of all members of the team.

The Reports section will, for now, be empty.

The Stories section should contain links to three pages titled “Roles”, “Increment 1”, and “Increment 2”. These pages can be empty for now.

2. Discuss within your team: What are the user roles relevant to this project?

In your Wiki, record your conclusions on the “Roles” page. List each user role and give a brief one or two sentence description.

3. Compose your stories. The sum total of your stories should span the required behaviors of the system.

Stories will be entered into the OpenProject tracking system.

In the later project phases, having these in OpenProject will help in tracking who is working on what stories, which stories are completed, andwhich have not yet been started.

Page 613: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Create a new story using the drop-down menu on the right of the Project Backlog header.

Mark as a “User story” (not “Feature”). Fill in the “As a … ” description. Leave the status as “New”.Hit “Enter” to create that story.

Click on the number of the newly created story to open up its full page.

Do not mark your stories as “assigned” to a team member. You will use that ability later when someone takes responsibility for implementingthat story.

In the Description, add any additional explanation necessary.

In particular, explain how implementing this story will affect visible behavior of the system. Will it produce an output report? Will itcause certain data appearing to become more accurate or more complete in some fashion?

You might need to speculate a bit on when you expect this story to be implemented, i.e., what parts of the system might not be workingyet. It’s OK to suggest that data being shown in output, for example, is likely to be “fake” values coming from a stub until some otherstory gets implemented.

If you like, you can use the Relations tab to indicate that this story needs to follow another one that has already been created.

Ideally, a story should indicate a unit of work that a programmer can complete within a single increment of the iterative development process.For our purposes, that amounts to something that a student programmer could complete within a week or two. (That should take into accountthe fact that students are not assigned full-time to this project.)

For each story, enter the effort level expected in the “Story Points” field.

If, upon review, you decide that a story is too large (an “epic”), do not delete it. Instead, change its type from “User Story” to “Epic”, split it intosmaller stories that use Relations to indicate that they are “part of” that epic.

5 Plan Your Increments1. In the Backlogs area, create two more Versions called “Increment 1” and “Increment 2”.

2. Agree on a collection of stories to serve as the first two increments (project phases 3 and 4, respectively).

Drag those stories from the Project Backlog to the appropriate Increments.

Important: Remember that each increment must add observable functionality to the system. That means that you must choose at least onestory that generates visible output. Think in vertical slices!

Page 614: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3. In the “Increment” pages of your Gitlab Wiki, add a paragraph or two of text describing what observable functionality will be available upon completionof that increment.

If you can’t do this easily, then you need to either redesign your stories or re-think your choice of stories for that increment.

Please remember that updating an internal data structure is not, in and of itself, observable.

And compiling your code and/or passing your unit tests does not count as functionality.

6 Peer EvaluationAfter your work has been completed, each team member must individually take the peer evaluation survey. The purpose of this survey is to assess the relativecontributions made by individual team members.

7 SubmissionThere is no formal submission activity – when the due date comes, I will examine your OpenProject and GitLab project areas.

8 EvaluationEvaluations will be a combination of what the group has accomplished and how much each individual contributed to that group’s effort.

8.1 Grading of Project PhasesThis phase will be graded as

score = quality * indiv

where:

quality is an assessment of the completeness, correctness, and quality of the stories and Wiki pages prepared by the team.

indiv is a scaling factor for an individual’s effort. A normal effort level is 1.0. This factor will be raised or lowered by a combination of

score on peer evaluation surveyswhether the individual contributed to the surveyactivity in the OpenProject tracker (as shown on each member’s Activity page), with a bonus for work done early in the phase.

Page 615: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Note: if you allow another team member to enter your stories into OpenProject for you, they will get credit for that activity and you will not.

Everyone in this course is supposed to demonstrate their ability to work with the various tools covered in this class. Do not appoint a team“scribe”, “secretary”, or “librarian” to do tool interaction for everyone else.

8.2 Common Problems with StoriesAs your stories are graded, I may make comments directly in your OpenProject tracker (these will appear as comments in the story detail) or in the spreadsheetin which your overall evaluation is tallied.

Some shorthand annotations that I may use for common problems are:

8.2.1 Definite Problems

ODCOnly the Developers Care

Stories about getting the build to work or getting unit tests written are not of interest to the end users, only to the developers.

That’s not to say that there isn’t effort required to do this stuff. but the effort is generally considered to be factored in to the effort to implement “real”stories.

Almost any story that begins “As a programmer…” or “As a software developer…” will be ODC (unless the project is itself a library or tool for use byother programmers and developers who are not members of the system’s own development team).

UTFUlysses Traveled Far

Refers to stories that aren’t merely epics, but summarize the working of the entire system, or of major subsystems, in a single sentence. Such storiescannot be completed in a single increment and are unhelpful in breaking the development effort into practical units of work.

Examples would be “Evaluate all expressions in a spreadsheet loaded from a file.” or “Generate monthly sales reports broken down by customers.”

These epic stories need to be broken down. Ask yourself why you wanted to write this in the first place. Is this, for example, the only mention of a report?Then devise a story to generate that report from data already loaded and summarized in the system, so that the loading and summarization can be added asseparate stories. Is this the only mention of reading data from a file? Then have a story (even if IB, see below) to load the data, and separate stories towork with it and to produce visible output after that work.

NUWNot a Unit of Work

Page 616: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

This describes stories that cannot be assigned as units of work during the development phase. Reasons might include that this is not done duringdevelopment (e.g., system reliability and usability requirements must be measured after the development is completed), and/or is an over-arching concern(e.g., “maintain communication with end users”, “use pair-programming”, “satisfy all mandatory requirements”).

NESNever Ending Story

A special case of NUW, this describes stories that cannot be assigned as distinct units of work because they will never be finished until all developmentwork is complete.

For example, you might have a requirement that the code must compile with the Java 8.0.1 compiler. But a story

As a developer, I want the code to compile with the Java 8.0.1 compiler.

would be an NES story (_and_ an ODC story). You can’t assign it to someone as a unit of work and expect them to complete it, because as long as anyoneelse is contributing any code, they could contribute something that breaks the requirement.

MTAIMy Teammates Are Idiots

Indicates a story that assumes a teammate will do a poor job on another, closely related story.

For example, suppose that you have a requirement stating that the system must keep sales data for a company’s customers and another requirement thatthe system must be capable of storing data on at least 500 customers.

If you wrote separate stories

As a ..., I would like to see sales data for customers. As a ..., I would like to see that data for up to 500 customers.

the second story would be an MTAI story. It assumes that whoever implements the first story will not have read the requirements and so will choose aninappropriately small data structure to store the data.

RITMRolling In The Mud

A common special case of MTAI. People like to pad out their stories by focusing on error conditions and messages.

For example, you might have a requirement to read in and process a positive number, with a required error message if the number is zero or negative.That’s one story - it doesn’t naturally break down into a “read and process this number” and a separate “Print the error message if the number is not

Page 617: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

positive” story.

Anyone implementing the first story will naturally inject the logic required for the second story. Certainly it makes little sense to assign one person theerror message story and someone else the read-and-process story (or even worse, to assign someone the error message story and defer the read-and-process story to a later increment). Yet, I’ve seen students who, after three increments of the project, have worked on nothing but printing error messages.

8.2.2 Possible problems

IBInvisible Behavior

Be careful of stories like “As a …, I want the system to read a data file X.”

Reading data into an internal data structure is not an observable behavior. You might claim to have done this, but how does an end user know that youreally have done it unless it directly affects the output somehow. (And, no, passing a unit test does not count because ODC.)

There’s two ways to deal with this kind of story.

1) Rewrite the story to establish a link to behavior, e.g., As a … I would like the customer listing to reflect the customers listed in the data file X."

2) Plan your increments so that an IB story is paired with an output-generating story (e.g., As an …, I would like to see a report listing all customers.) andmake sure that someone is assigned the output story before the input story, so that if you don’t finish all scheduled stories by the end of the increment,you still have a visible behavior to demonstrate to the end user.

Add comments in the tracker to your IB story indicating which out-producing stories it is intended to be paired with.

Page 618: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Project Phase 3: Build Management and Version ControlCS350

Last modified: Feb 20, 2020

Contents:1 Building

1.1 Demonstrating Test-Driven Development2 Submission3 Peer Evaluation4 Tips

4.1 What to Work on4.2 Working as a Team

5 Evaluation5.1 Grading of Project Phases

6 Design Brainstorming Session6.1 Prior to the meeting6.2 During the Meeting

7 Project Review Meetings7.1 Conduct of the Meeting7.2 Meeting Via Network Conferencing

In this phase of the project, you will begin the software construction process. Your priorities during this phase will be setting up and learning to use yourproject’s version control repository and automating your build.

Your reference materials for this phase include

the requirements definitionthese design notes

Review your grades from Phase 2 (stories). The detailed grade spreadsheet contains my own list of stories. If you are missing any of them, you may havefailed to account for portions of the work required to finish this project. You should consider adding some of those to your own list of stories, because I willcontinue to use those, in the future phases, as a basis for estimating how much of the project functionality you have implemented. If you do not have statementsthat describe the work you have done, you might not get credit for having done it.

1 Building

Page 619: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. Working from your GitLab project area, create a git repository for your project.

Your project directories must be organized according to the Android conventions.

All code for this project should reside in the package edu.odu.cs.cs350. Sub-packages of that are permitted.

Each team member should follow the procedure outlined in the GitLab assignment to identify yourself so that all commits you make are listedunder your CS login name.

If you work on multiple clones of the repository (e.g., on different machines), you need to do this on each clone.

2. Work on implementing the stories for at least the first increment identified by your team.

Follow the process described below in Demonstrating Test-Driven Development to track your progress on this increment.

All APIs contributing to a story must be validated by appropriate unit tests.All classes must include meaningful documentation.

3. Using gradle, automate the build of the project components so far. This must include all unit tests. The build must run all unit tests and (for now)whether those are passed or not, package the non-test components of the project as a Jar file.

Use the gradle wrapper so that all team members are using a consistent builder.

4. As you add components to the project, check them into the repository using git.

Material placed under version control should include all source code, hand-edited data files, etc., as well as the build manager settings files.

Do not include binaries produced by compiling your own code, Jars or other binaries of 3rd-party libraries you have imported, etc.

Do not include the Eclipse .project and .classpath files.

Include the .gitignore file(s). In fact add this file first!.

Do include the gradle wrapper gradlew* files and the associated gradle/ directory.

You may use branches to explore implementation alternatives. But your team’s main codeline should be the master/origin branch. That is where Iwill look for your code, and your grade will be based in part upon your contributions to that branch.

5. Your project will eventually make use of a number of third-party libraries. Refer to the Design Notes linked at the top of this document for details.

When starting out, you may not need all of these. Refer to the design notes for instructions on how to load these libraries automatically as part of yourbuild. (We’ll examine how this really works in more detail later.)

Page 620: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1.1 Demonstrating Test-Driven DevelopmentYou are required to follow the principles of test-driven development and to document your practices in doing so.

1. Your stories are divided into increments on the Open Project Board. For each story that you are working on, create tasks to guide and capture yourprogress.

2. At a minimum, you should have the following tasks for each story:

Develop the code.

This includes writing the tests to drive the code.This task is not completed until you have passed all of your unit tests for this story.This task is not completed unless the code is committed and pushed, with any version conflicts resolved.If the story is large and/or complicated and naturally decomposes into separate pieces, you may want to have several of these “develop”tasks, one for each piece.

Create a system test.

You will have developed unit/integration tests already. But you need at least one system test designed to demonstrate that the story will hold whenthe entire system is available.

Integrate the new code

Show that any new or modified functions involved in this story are used elsewhere in the existing code base, so that your API interfaces developedin this story are known to be usable.

3. As you make progress on your stories, drag the tasks to the appropriate column of your task board.

4. Carry your tasks through to completion – don’t flit from one to the other.

As a general rule, any one person should have only one task “in progress” at a time.

Exceptions to this rule should be rare, and you should be prepared to be questioned on any violations.

If you find it impossible to make progress on a task that you have started, move it to the “On hold” column. Then add a “task” to the SprintImpediments row containing the story # of the task you are abandoning and a brief explanation of why you chose to set it aside.

If you fail to update your agile board, your group may not get credit for work accomplished. If you move the cards forward without adding theexplanatory notes, I might not believe your claim to have finished something.

Page 621: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

2 Submission“Submit” your project for this phase by tagging the version as “phase3”. Note: this must be a simple tag, a name attached to a particular snapshot in themain/origin branch, not a new branch.

3 Peer EvaluationEach team member must individually take the peer evaluation survey at the end of the phase. The purpose of this survey is to help assess the contribution madeby individual team members.

4 Tips4.1 What to Work on

Be incremental, not just iterative.

Incremental development is characterized by the addition of observable behavior of value to the end users by the end of each increment. Each of phases3..5 should be an increment.

It’s essential, therefore, that one of the first stories tackled should be one that produces a report or other observable output. The output for the firstincrement may be of data that has been largely faked. That’s OK, in later increments you can point out the changes in that output as “real” datastarts getting produced. Those changes will be the evidence that progress is being made.

This requires coordination among your team members in your choice of initial stories to tackle. So talk to each other. Make sure that you have ateam plan, not a half dozen individuals’ plans.

There seems to be a real temptation for people to jump on “input” stories early on. I’ve seen teams where everyone wants to work on the CLI.Resist that temptation.

It’s easy to provide “cooked” or faked inputs to various phases of the program. It’s much harder to claim that you are making progress if yourchosen stories have no visible effect on the output.

Stories like “As a … I want to load the input file.” are treacherous in the early increments. When you are demonstrating your program, you may tellme that you have loaded data, but I can’t see (and wouldn’t care to see) your internal data structures. For all I know, all you have done is to print amessage saying that you laoded it (if you have even done that much).

Go deep rather than broad.

Page 622: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Each team member should pick a story and push it through interface design, test case design, and implementation to the start of integration.

Don’t pick 4 stories and move them into “Interface Design” and then leave them there. That does not actually contribute any observable functionality tothe increment.

Get the infrastructure done early.

Each of phases 3..5 will require you to add some project infrastructure such as standardized directories, git repositories, build files, etc. Get that done asearly as possible.

These aren’t part of any stories. But until the infrastructure isn’t set up, no one will make appreciable progress on their stories.

4.2 Working as a TeamFor this and all subsequent phases, remember that you are working as a team. That does not mean that you are yoked together like a team of horses that arriveat a job together, pull together in lockstep, and then are sent off at the end of the task all at the same time. You’re going to be working independently, but have tomake sure that you don’t abuse that independence to the detriment of the team.

It is expected in a team project that other people will be using or building upon the code or other software artifacts that you are working on. Yourteammates are depending upon you.

If you wait until the last day or two of each phase to do your tasks, you’ve let your team down because they will not have time to build upon yourwork or to make sure that your work integrates properly with theirs.

Even if you have done the work early, if you do not check it in to the team’s repository and make it available to them, you’ve still let your teamdown.

Set aside regular periods of time to work on this project.

Your team will be much better served by your working 30 minutes every other day for 14 days of a phase than by your working 7 hours on the 14th day.

Don’t think for a moment that your instructor hasn’t noticed that 75% of the class never submit an assignment more than 24 hours before it are due,or that 50% of the emailed questions about assignments come in the last 4-8 hours before the final deadline.

That sort of procrastinatory brinkmanship might work for you on an individual assignment, but is deadly to team projects.

Some of your credit for your individual contribution to the project will be weighted according to how early you acted.

Try to set up each work period with a specific goal in mind. For example, you might devote one work period to writing one or two unit tests. If that’s allyou get done, fine. You still have made observable progress.

Page 623: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Most people work much better if they have a specific goal in mind, and this also helps limit the scope of the changes so that you can easily commit them.Which brings us to the next point…

At the end of your work period, commit your changes. If your work is seriously incomplete and might break things for your teammates, check it in toyour local copy of the repository but don’t push it to the team shared repository.

But don’t go too long before pushing your work to the team repository. That risks version conflicts that will be time-consuming to resolve.

Get into the habit of beginning each work session by pulling all changes from the team repository, so that, if your work is in conflict, you resolvethat as early as possible.

Your team should try to get any shared “infrastructure” for the phase completed within the first first days of the phase. Examples would be setting up therepository, setting up the project directory structure, and setting up the build manager files.

That way the support structure is already in place when you get down to the “real” development work.

If you make changes to any public ADT interface, commit and push those changes as soon as possible. By definition, such changes have the potential tostrongly affect the work of your teammates.

For example, if you are following the principles of TDD, you will start by asking whether the ADTs involved in your current story present the appropriatepublic functions to allow you to test the story’s behavior. If you add add public functions or modify the names/parameters of existing ones, you shouldcommit and push those changes ASAP.

Don’t wait until you have completed the unit tests or, worse, until you have actually finished implementing the behavior. You might not get allthat done until days later. Changes to public interfaces are things that your teammates need to know about as soon as possible.

5 EvaluationEvaluations will be a combination of how much the group has accomplished and how much each individual contributed to that group’s effort.

The login name / account used to create or edit stories or to commit code changes to the project will be also used as evidence of the individual’s efforts. Thismeans that you should not appoint some students as scribes/librarians to record others’ work. Doing so will guarantee that the librarian gets credit for everyoneelse’s work.

Your team’s progress will be measured both in terms of what has been submitted and in a project review meeting. Refer to the more detailed description of theproject review meetings below.

5.1 Grading of Project PhasesPhases 3..5 will be graded as

Page 624: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

score = ( process * progress + review ) * indiv

where:

progress is an assessment of the completeness, correctness, and quality of the work completed on the project.

This is primarily based on stories completed, with the understanding that stories were scaled to reflect the amount of work that one student couldcomplete in one 2-3 week increment.

The amount of code checked in is also considered, but the weight shifts more and more towards the stories as we progress to the later phases.

A normal progress level is 1.0. Teams that complete more stories will receive numbers above 1.0 and teams that complete fewer will receivenumbers below 1.0.

process is an assessment of how well your team has set up its process, including use of required/recommended tools.

You can find the details of the items assessed for process in this spreadsheet.Some of the items in the PROCESS section of that spreadsheet are not evaluated until later phases. The starting phase number for each item isindicated separately. The relative weights given to each item will depend on what phase we are in.

review refers to the individual’s performance in the review meeting.

indiv is a scaling factor for an individual’s effort. A normal effort level is 1.0. This factor is evaluated by a combination of

peer evaluation surveystasks completed on user stories as documented on the task board,number of commitsnumber of work sessions

A work session is an 8-hour period within which you make one or more commits. This measure is intended to reward people who work steadilyduring the weeks that make up the phase, making their work available to their teammates, and to penalize the people who show up for work in thefinal 12-24 hours and try to rush in a bunch of stuff in panic mode.

6 Design Brainstorming SessionNear the beginning of Phase 3, we will conduct a design “brainstorming” session during your recitation period. The purpose of this session is to:

1. arrive at a group consensus of the major components of the system design.2. check the status of your stories in Redmine.3. check the status of your Git Repository

Attendance is mandatory.

Page 625: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

6.1 Prior to the meeting1. review our earlier discussion of Object-Oriented Analysis, particularly the object-oriented philosophy and the idea of modeling in terms of interacting

objects. CS330 students may want to review the process of “classification”, which lies at the heart of the analysis that we will be doing.

6.2 During the MeetingDon’t wait for the instructor to join your session. Start to work immediately.

1. At the start of your meeting, one person should create a Google Doc editable by all team members and by [email protected] and share the URL to that.Make sure that your group name is part of the document file name.

2. Based upon the requirements and design notes, propose classes that you think will be essential to this project. Propose the major operations on these.Sketch these out in your shared document.

Document your discussion continuously.

As you discover useful classes, document their names, attributes, and operations. You may use UML diagrams as you practiced in our earliersession or in plain text as C++/Java class interfaces.

If you discover useful relationships between classes, show those as UML diagrams.

Don’t worry about syntax and don’t waste time trying for perfection here. But do try to record things clearly enough so that someone canidentify the classes, operations, and the major inputs/outputs of those functions.

Your first concern should be identifying classes that simulate the critical real-world objects.

When in doubt, “keep it real”!

A secondary (but still legitimate) concern is identifying classes that will be used as the implementing data structure for classes you have alreadydevised. Don’t lock yourself into too much detail here. It’s too early, for example, to worry about whether something will be an array, vector, or list.But you may want to note that “class A will store a sequence of B”.

In assigning operations to classes, remember this rule:

If A does B to C in the real world then, in most cases, our model of the world as interacting objects should say that

B(...) is a function method of class C (not A).Somewhere inside the body of some other method of class A, we expect to find that A calls C.B(...).

Page 626: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

3. After teams have had a little while to get the process going, the instructor will start moving from one team meeting to another to see how you are doingand offer suggestions where appropriate. The timing will depend on how much time is spent with other teams. Yours may be visited once, or multipletimes.

4. After the meeting has concluded, add a link to the home page of your project Wiki to your shared design document.

7 Project Review MeetingsThese meetings will be held during the recitation periods, as announced on the course outline.

Meetings will be held by network conferencing (Google Meet). More details on network conferencing meetings is below.

This course is about tools and techniques to support software construction, not about programming specifically. Getting the project to work will count as part ofthe grade, but is not the only part and may not be the most important part, except in as much as it demonstrates mastery of the relevant tools and techniques.

7.1 Conduct of the MeetingAttendance at the scheduled review meeting is mandatory and counts toward the individual component of your score.

Please be on time. I will have only limited time with each team before I need to move on to my next meeting with another team. Making everyone waitwhile you struggle to enter the conference, play with your settings, etc., is unacceptable.

You should be in the conference area and ready to go at the announced starting time for the meeting. You can (and probably should) arrive early to getyourself set up.

At the start of the meeting, you must already have Eclipse open and ready with your own copy of your team’s project.

This needs to be opened as an Eclipse java and/or Gradle project in the Java project view, not simply as an unused clone in the Git repository view.

The version you have open should be the one submitted at the end of the phase. E.g., for phase 3 of the project, this would be the version that wastagged by your team as “phase3”.

If you have done additional work since the submission and are worried about losing it, make a fresh clone of your team’s project in a separatedirectory, check out the “phase?”-tagged version, and use that for the meeting.

You must be prepared to show your session via screen sharing. That includes having re-sized the window to a conservative size (e.g., 800x600) sothat the shared image will be readable on other peoples’ screens.

During the meeting, I may ask the team to show that they have completed part of the assignment or to explain part of what they have done. I may callupon specific individual team members to explain or to demonstrate techniques relevant to the phase.

Page 627: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

At the end of the meeting, your team may be given a short task to perform on an individual basis. You will have a limited time (less than a day, possiblyas little as one hour) to do this and to submit the results.

An individual who is unable to complete a required task or answer a directed question to my satisfaction will lose individual score points. If a second individualin likewise unable to complete that task or to answer the question, then the overall team score will be reduced.

7.2 Meeting Via Network ConferencingMeetings will be conducted via Google Meet. You will receive an email prior to the meeting containing a link that will take you to the meeting.

You must have a functioning microphone & audio setup for the meeting. A web camera is optional but recommended.

You must be in a place where you can both hear and be heard. Avoid trying to participate from locations with high levels of background noise (e.g.,public areas in Webb center).

You should be able to enter the meeting area early.

This will allow you to be sure that your audio/video setup is working and that you have up-to-date versions of the browser plugins required.

If there are multiple teams being reviewed in a given recitation/class period and yours is not the first, the instructor will be in a separate hangoutsarea with the earlier team. Please be patient if the instructor is a bit late getting to you.

By the same token, the time to meet with your team is limited. You may be penalized if you are not ready to meet at the appointed time.

Page 628: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

Project Phase 4: Reporting and Continuous IntegrationCS350

Last modified: Mar 18, 2020

Contents:1 Adjust Your Planning2 Continue Building3 Evaluation4 Project Review Meetings

In this phase of the project, you will continue the software construction process. Your priorities during this phase will be adding reporting features to your buildto update your website with JavaDoc documentation and test reports, configuration management to your automated build and exploiting continuous integrationto perform system analysis and testing.

Your reference materials for this phase include

the requirements definitionthese design notes

1 Adjust Your PlanningIn the 1st 72 hrs. of the phase:

Your team should do the following, in consultation with one another:

1. Go to Open Project and examine your progress in Phase 3. How many story points worth of stories did your team complete? You can allow partial creditfor stories advanced but not completed.

In your project Wiki on GitLab, go to your Increment 1 page and document that number of story points.

2. Some teams will do better in phase 4 than in phase 3, sometimes because they are now more familiar with the development process and sometimesbecause a poor phase 3 lends a sense of urgency to phase 4.

Set a target for number of story points to complete in phase 4. Unless you think you were really loitering in phase 3, this should probably be no more than1.5 to 2.0 times the number of points completed in phase 3. (On the other hand, if that still works out to less than one point per team member, you mightwant to question why.)

Page 629: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

In your project Wiki on GitLab, go to your Increment 2 page and document that number of story points that you plan to complete.

3. Move any stories that were started but uncompleted in phase 3 from your Increment 1 backlog to your Increment 2 backlog.

4. Review your plans for what observable behavior you expect to be able to demonstrate at the end of Increment 2. If this needs to changed, document thenew planned observable behavior in your Increment 2 page.

5. Move stories out of your Increment 2 backlog, returning them to the Project Backlog, until the number of points worth of stories in Increment 2 isapproximately equal to the planned number you selected in step 2.

Choose the stories to remove in a manner consistent with your planned demonstration from step 4. Remove those stories that do not contribute to theplanned demonstration.

2 Continue Building1. Continue your build, following the TDD procedures of the prior phase.

2. Choose a location from which to serve web pages containing project status reports. You will need a mechanism by which you can permit any teammember to update these pages. The file drop areas you created using ssh keys would be ideal for this purpose.

Create a “Reports” web page there with the names of and links to the reports that you are posting (see below).

Add a link to your reports web page in the Reports section of your Wiki opening page.

3. Modify your build so that an appropriate target (e.g., “reports”) guarantees that both updated Javadocs and JUnit test reports are generated.

4. Place the project under continuous integration, using the gitlab-ci function of GitLab. * Your GitLab project should automatically build your projectafter each commit to the master branch. * It should upload updated Javadocs and JUnit reports to the website after each build. If you do not have a targetin the build to accomplish this, you may do so via the CI script. * The required ssh key should be supplied as a GitLab secret variable. * Each team hastheir own runner, identified by the color-number convention, e.g., “blue1”, “yellow2”, “green1”, etc. Select your team’s runner by entering that name inthe tags area of your gitlab-ci.yml file.

Do not enter any other tags, and do not use another team's runner!

Do this as early in phase 4 as practical. Part of your grade will depend on how complete a historical record you establish during this phase.

5. Add test coverage and at least one static analysis tool to the build.

Coverage should be computed using both unit and integration tests.Publish your coverage and static analysis reports on your Reports web page.

Page 630: Introduction to Software Engineeringzeil/cs350/latest/4x3.pdf · 5. Apply the mutator/accessor strategy for ADT testing. 6. Discuss the use of mock objects in unit testing. Relevance

1. Add integration and systems tests. A “systems test” in this project would be an execution from the Jar file you have constructed as a build artifact.

Note that you should have been designing systems tests as part of your normal procedure for implementing stories.

2. “Submit” your project for this phase by tagging the version to be reviewed as “phase4”.

3. Each team member must individually take the peer evaluation survey.

3 EvaluationEvaluations will be conducted as was done in Phase 3.

4 Project Review MeetingsThis phase concludes with a project review meeting, conducted according to the same guidelines as in phase 3.