Post

CS2103T Week 8 & 9

CS2103T Week 8 Topics

Revisiting Class/Object/Sequence Diagrams

Refer to previous post (Week6-7).

Testing: Types

Integration Testing (Compared to Unit Testing)

Integration testing: testing whether different parts of the software work together (i.e. integrates) as expected. Integration tests aim to discover bugs in the ‘glue code’ related to how components interact with each other. These bugs are often the result of misunderstanding what the parts are supposed to do vs what the parts are actually doing.

How?:

Integration testing is not simply a case of repeating the unit test cases using the actual dependencies (instead of the stubs used in unit testing).

  • Instead, integration tests are additional test cases that focus on the interactions between the parts.
  • In practice, developers often use a hybrid of unit+integration tests to minimize the need for stubs.

System Testing

System testing: take the whole system and test it against the system specification.

System testing is typically done by a testing team (also called a QA team).

  • System test cases are based on the specified external behavior of the system.
  • Sometimes, system tests go beyond the bounds defined in the specification. This is useful when testing that the system fails ‘gracefully’ (show some meaning error message etc.) when pushed beyond its limits.
  • System testing includes testing against non-functional requirements too.

Automated Testing of GUIs: If a software product has a GUI (Graphical User Interface) component, all product-level testing (i.e. the types of testing mentioned above) need to be done using the GUI. However, testing the GUI is much harder than testing the CLI (Command Line Interface) or API, for the following reasons:

  • Most GUIs support large number of different operations, many of which can be performed in any arbitrary order.
  • GUI operations more difficult to automate than API testing. Reliably automating GUI operations and automatically verifying whether the GUI behaves as expected is harder than calling an operation and comparing its return value with an expected value. Therefore, automated regression testing of GUIs is rather difficult.
  • Appearance of a GUI (and sometimes even behavior) can be different across platforms and even environments. For example, a GUI can behave differently based on whether it is minimized or maximized, in focus or out of focus, and in a high resolution display or a low resolution display.
  • Moving as much logic as possible out of the GUI can make GUI testing easier. That way, you can bypass the GUI to test the rest of the system using automated API testing.
  • Some testing tools: TestFX, Visual Studio ‘record replay’, Selenium.

Acceptance Testing

Acceptance testing (aka User Acceptance Testing (UAT)): test the system to ensure it meets the user requirements.

Acceptance tests give an assurance to the customer that the system does what it is intended to do. Acceptance test cases are often defined at the beginning of the project, usually based on the use case specification. Successful completion of UAT is often a prerequisite to the project sign-off.

  • Acceptance testing comes after system testing. Similar to system testing, acceptance testing involves testing the whole system.

Some differences between system testing and acceptance testing:

  • System Testing done against the system specification, Acceptance Testing done against the requirements specification

Alpha/Beta Testing

Alpha testing is performed by the users, under controlled conditions set by the software development team.

Beta testing is performed by a selected subset of target users of the system in their natural work setting.

An open beta release is the release of not-yet-production-quality-but-almost-there software to the general population. For example, Google’s Gmail was in ‘beta’ for many years before the label was finally removed.

Exploratory vs. Scripted Testing

Here are two alternative approaches to testing a software: Scripted testing and Exploratory testing.

Scripted testing: First write a set of test cases based on the expected behavior of the SUT, and then perform testing based on that set of test cases.

Exploratory testing: Devise test cases on-the-fly, creating new test cases based on the results of the past test cases.

Exploratory testing is ‘the simultaneous learning, test design, and test execution’. Testing is driven by observations during testing. Exploratory testing usually starts with areas identified as error-prone, based on the tester’s past experience with similar systems. One tends to conduct more tests for those operations where more faults are found.

  • Exploratory testing is also known as reactive testing, error guessing technique, attack-based testing, and bug hunting.

Which approach is better – scripted or exploratory? A mix is better.

The success of exploratory testing depends on the tester’s prior experience and intuition. Scripted testing is more systematic, and hence, likely to discover more bugs given sufficient time, while exploratory testing would aid in quick error discovery, especially if the tester has a lot of experience in testing similar systems.

Testing: Intermediate Concepts

Dependency Injection

Dependency injection is the process of ‘injecting’ objects to replace current dependencies with a different object. This is often used to inject stubs to isolate the SUT from its dependencies so that it can be tested in isolation.

  • Polymorphism can be used to implement dependency injection.

Testability

Testability is an indication of how easy it is to test an SUT. As testability depends a lot on the design and implementation, you should try to increase the testability when you design and implement software. The higher the testability, the easier it is to achieve better quality software.

Test Coverage

Test coverage is a metric used to measure the extent to which testing exercises the code i.e., how much of the code is ‘covered’ by the tests.

Here are some examples of different coverage criteria:

  • Function/method coverage: based on functions executed e.g., testing executed 90 out of 100 functions.
  • Statement coverage: based on the number of lines of code executed e.g., testing executed 23k out of 25k LOC.
  • Decision/branch coverage: based on the decision points exercised e.g., an if statement evaluated to both true and false with separate test cases during testing is considered ‘covered’.
  • Condition coverage: based on the boolean sub-expressions, each evaluated to both true and false with different test cases. Condition coverage is not the same as the decision coverage.
  • Path coverage: measures coverage in terms of possible paths through a given part of the code executed. 100% path coverage means all possible paths have been executed. A commonly used notation for path analysis is called the Control Flow Graph (CFG).
  • Entry/exit coverage: measures coverage in terms of possible calls to and exits from the operations in the SUT.

Measuring coverage is often done using coverage analysis tools. Most IDEs have inbuilt support for measuring test coverage, or at least have plugins that can measure test coverage.

Coverage analysis can be useful in improving the quality of testing e.g., if a set of test cases does not achieve 100% branch coverage, more test cases can be added to cover missed branches.

TDD: Test Driven Development

Test-Driven Development(TDD) advocates writing the tests before writing the SUT, while evolving functionality and tests in small increments.

  • In TDD you first define the precise behavior of the SUT using test code, and then update the SUT to match the specified behavior.
  • While TDD has its fair share of detractors, there are many who consider it a good way to reduce defects. One big advantage of TDD is that it guarantees the code is testable.

Note that TDD does not imply writing all the test cases first before writing functional code. Rather, proceed in small steps:

  1. Decide what behavior to implement.
  2. Write/modify a test case to test that behavior.
  3. Run the test cases and watch them fail.
  4. Implement the behavior.
  5. Run the test cases.
  6. Keep modifying the code and rerunning test cases until they all pass.
  7. Refactor code to improve quality.
  8. Repeat the cycle for each small unit of behavior that needs to be implemented.

CS2103T Week 9 Topics

OODMS (OO Domain Models): Conceptual Class Diagrams

While thinking about the problem domain, we think about object, class structures.

When building an OOP system, it makes sense to build OOP models of the problem domain, given OOP aspires to emulate the objects in the real world.

The UML model that captures class structures in the problem domain are called conceptual class diagrams. They are in fact a lighter version of class diagrams, and sometimes also called OO domain models (OODMs). The latter name is somewhat misleading as conceptual class diagrams (CCDs) are actually only one type of domain models that can model an OOP problem domain.

CCDs do not contain solution-specific classes (i.e. classes that are used in the solution domain but do not exist in the problem domain). For example, a class called DatabaseConnection could appear in a class diagram but not usually in a CCD because DatabaseConnection is something related to a software solution but not an entity in the problem domain.

CCDs represents the class structure of the problem domain and not their behavior, just like class diagrams. To show behavior, use other diagrams such as sequence diagrams.

CCD notation is a subset of the class diagram notation (omitsmethods and navigability).

Activity Diagrams

Software projects often involve workflows. Workflows define the flow in which a process or a set of tasks is executed. Understanding such workflows is important for the success of the software project.

UML activity diagrams (AD) can model workflows. Flow charts are another type of diagram that can model workflows. Activity diagrams are the UML equivalent of flow charts.

An activity diagram (AD) captures an activity through the actions and control flows that make up the activity.

  • An action is a single step in an activity. It is shown as a rectangle with rounded corners.
  • A control flow shows the flow of control from one action to the next. It is shown by drawing a line with an arrow-head to show the direction of the flow.
  • A branch node shows the start of alternate paths. Each control flow exiting a branch node has a guard condition: a boolean condition that should be true for execution to take that path. Exactly one of the guard conditions should be true at any given branch node.
  • A merge node shows the end of alternate paths.
  • Fork nodes indicate the start of concurrent flows of control.
  • Join nodes indicate the end of parallel paths.
  • The rake notation is used to indicate that a part of the activity is given as a separate diagram.
  • It is possible to partition an activity diagram to show who is doing which action. Such partitioned activity diagrams are sometime called swimlane diagrams.

Conceptualizing a Design

You can use models to analyze and design software before you start coding.

  • Should be able to use simple class diagrams and sequence diagrams to model an OO solution.

Architecture Diagrams

Drawing Architecture Diagrams: While architecture diagrams have no standard notation, try to follow these basic guidelines when drawing them.

  • Minimize the variety of symbols. If the symbols you choose do not have widely-understood meanings e.g. A drum symbol is widely-understood as representing a database, explain their meaning.
  • Avoid the indiscriminate use of double-headed arrows to show interactions between components.

Design Principles

SOLID Design Principles:

  • Single responsibility principle
    • Single responsibility principle (SRP): A class should have one, and only one, reason to change.
    • If a class has only one responsibility, it needs to change only when there is a change to that responsibility.
  • Open-closed principle
    • Open-closed principle (OCP): A module should be open for extension but closed for modification. That is, modules should be written so that they can be extended, without requiring them to be modified.
    • We should be able to change a software module’s behavior without modifying its code (but by extending its code, perhaps).
  • Liskov substitution principle
    • Liskov substitution principle (LSP): Derived classes must be substitutable for their base classes.
    • LSP implies that a subclass should not be more restrictive than the behavior specified by the superclass.
    • If LSP is not followed, substituting a subclass object for a superclass object can break the functionality of the code.
  • Interface segregation principle (ISP)
    • No client should be forced to depend on methods it does not use.
  • Dependency inversion principle (DIP):
    • High-level modules should not depend on low-level modules. Both should depend on abstractions.
    • Abstractions should not depend on details. Details should depend on abstractions.
    • Use interfaces instead of classes themselves.

Other Good Design Principles:

  • Separation of concerns principle
    • Separation of concerns principle (SoC): To achieve better modularity, separate the code into distinct sections, such that each section addresses a separate concern.
    • Applying SoC reduces functional overlaps among code sections and also limits the ripple effect when changes are introduced to a specific part of the system.
    • This principle can be applied at the class level, as well as at higher levels.
    • This principle should lead to higher cohesion and lower coupling.
  • Law of Demeter
    • An object should have limited knowledge of another object. An object should only interact with objects that are closely related to it.
    • Don’t talk to strangers. Principle of least knowledge.
    • LoD aims to prevent objects from navigating the internal structures of other objects.

SDLC Process Models Continued

Software development goes through different stages such as requirements, analysis, design, implementation and testing. These stages are collectively known as the software development lifecycle (SDLC).

Agile Models

In 2001, a group of prominent software engineering practitioners met and brainstormed for an alternative to documentation-driven, heavyweight software development processes that were used in most large projects at the time. This resulted in something called the agile manifesto (a vision statement of what they were looking to do).

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan That is, while there is value in the items on the right, you value the items on the left more – Extract from the Agile Manifesto

Subsequently, some of the signatories of the manifesto went on to create process models that try to follow it. These processes are collectively called agile processes. Some of the key features of agile approaches are:

  • Requirements are prioritized based on the needs of the user, are clarified regularly (at times almost on a daily basis) with the entire project team, and are factored into the development schedule as appropriate.
  • Instead of doing a very elaborate and detailed design and a project plan for the whole project, the team works based on a rough project plan and a high level design that evolves as the project goes on.
  • There is a strong emphasis on complete transparency and responsibility sharing among the team members. The team is responsible together for the delivery of the product. Team members are accountable, and regularly and openly share progress with each other and with the user.

There are a number of agile processes in the development world today. eXtreme Programming (XP) and Scrum are two of the well-known ones.

Agile SDLC Process Model: Scrum

Scrum is a process skeleton that contains sets of practices and predefined roles.

The main roles in Scrum are:

  • The Scrum Master, who maintains the processes (typically in lieu of a project manager)
  • The Product Owner, who represents the stakeholders and the business
  • The Team, a cross-functional group who do the actual analysis, design, implementation, testing, etc.

A Scrum project is divided into iterations called Sprints. A sprint is the basic unit of development in Scrum. Timeboxed (i.e. restricted to a specific duration) effort of a constant length.

  • Each sprint is preceded by a planning meeting, where the tasks and estimated commitment for the sprint goal is made, and followed by a review or retrospective meeting, where the progress is reviewed and lessons for the next sprint are identified.

  • During each sprint, the team creates a potentially deliverable product increment (for example, working and tested software).
  • Scrum enables the creation of self-organizing teams by encouraging co-location of all team members, and verbal communication between all team members and disciplines in the project.
  • A key principle of Scrum is its recognition that during a project the customers can change their minds about what they want and need (often called requirements churn), and that unpredicted challenges cannot be easily addressed in a traditional predictive or planned manner. As such, Scrum adopts an empirical approach—accepting that the problem cannot be fully understood or defined, focusing instead on maximizing the team’s ability to deliver quickly and respond to emerging requirements.

  • Daily Scrum is another key scrum practice.
    • In Scrum, on each day of a sprint, the team holds a daily scrum meeting called the “daily scrum.”
      • What did you do yesterday?
      • What will you do today?
      • Are there any impediments in your way?

Agile SDLC Process Model: XP

Extreme Programming (XP) stresses customer satisfaction. * Instead of delivering everything you could possibly want on some date far in the future, this process delivers the software you need as you need it.

  • XP aims to empower developers to confidently respond to changing customer requirements, even late in the lifecycle.

  • XP emphasizes teamwork.
  • XP aims to improve a software project in five essential ways: communication, simplicity, feedback, respect, and courage.
  • XP has a set of simple rules. XP is a lot like a jig saw puzzle with many small pieces. Individually the pieces make no sense, but when combined together a complete picture can be seen.
  • Pair programming, CRC cards, project velocity, and standup meetings are some interesting topics related to XP. Refer to extremeprogramming.org to find out more about XP.

Other SDLC Process Models include Unified Process and CMMI (Capability Maturity Model Integration).

Writing Developer Documents

Developer-to-developer documentation can be in one of two forms:

  • Documentation for developer-as-user: Software components are written by developers and reused by other developers, which means there is a need to document how such components are to be used.
  • Documentation for developer-as-maintainer: There is a need to document how a system or a component is designed, implemented and tested so that other developers can maintain and evolve the code.

There is a secret that needs to be understood in order to write good software documentation: there isn’t one thing called documentation, there are four. They are: tutorials, how-to guides, explanation and technical reference. They represent four different purposes or functions, and require four different approaches to their creation. Understanding the implications of this will help improve most software documentation

  • TUTORIALS: learning-oriented, allows the newcomer to get started, is a lesson.
  • HOW-TO GUIDES goal-oriented, shows how to solve a specific problem, is a series of steps.
  • EXPLANATION understanding-oriented, explains provides background and context.
  • REFERENCE: information-oriented, describes the machinery, is accurate and complete, like a reference encyclopedia article.

Software documentation (applies to both user-facing and developer-facing) is best kept in a text format for ease of version tracking. A writer-friendly source format is also desirable as non-programmers (e.g., technical writers) may need to author/edit such documents.

  • As a result, formats such as Markdown, AsciiDoc, and PlantUML are often used for software documentation.

Documentation Guidelines

Aim for Comprehensibility: Technical documents exist to help others understand technical details. Therefore, it is not enough for the documentation to be accurate and comprehensive; it should also be comprehensible.

  • Use plenty of diagrams
  • Use plenty of examples
  • Use simple and direct explanations
  • Get rid of statements that do not add value
  • It is not a good idea to have separate sections for each type of artifact, such as ‘use cases’, ‘sequence diagrams’, ‘activity diagrams’, etc. Such a structure, coupled with the indiscriminate inclusion of diagrams without justifying their need, indicates a failure to understand the purpose of documentation. Include diagrams when they are needed to explain something. If you want to provide additional diagrams for completeness’ sake, include them in the appendix as a reference.

Describe Top-Down When writing project documents, a top-down breadth-first explanation is easier to understand than a bottom-up one.

  • The main advantage of the top-down approach is that the document is structured like an upside down tree (root at the top) and the reader can travel down a path she is interested in until she reaches the component she is interested to learn in-depth, without having to read the entire document or understand the whole system.

Minimal but Sufficient Aim for ‘just enough’ developer documentation.

  • Writing and maintaining developer documents is an overhead. You should try to minimize that overhead.
  • If the readers are developers who will eventually read the code, the documentation should complement the code and should provide only just enough guidance to get started.
  • Focus on providing higher level information that is not readily visible in the code or comments.
  • Describe the similarities in one place and emphasize only the differences in other places
This post is licensed under CC BY 4.0 by the author.