← Back to Module 1

Requirements and Use Cases

Introduction

As a Quality Assurance Engineer, you'll be responsible for ensuring that software meets its requirements. This involves understanding both functional and non-functional requirements, and creating test cases to verify them.

At Amazon, and in general software development, a Quality Assurance Engineer (QAE) works with developers to ensure that products are high quality. "Quality" describes how well something does its job. Therefore, to determine if our software is high quality, we have to describe its job.

Usually, customers give us requirements, telling us what they want our software to do. We refine these into simple stories about how the customer will use our software. Each story is a use case.

Use cases help us understand and improve our requirements. Once we have finalized our use cases, we use them to determine whether our software does its job: whether it is high quality.

Types of Requirements

Functional Requirements

Functional requirements describe what the software should do. They specify the behavior and features of the system. Examples include:

Non-Functional Requirements

Non-functional requirements describe how the software should perform. They specify qualities and constraints of the system. Examples include:

SDEs and QAEs work together to write and perform tests that prove our software does what the customer expects. Although their areas of responsibility are not cleanly separated, SDEs generally spend most of their effort on functional requirements and tests, and QAEs handle most non-functional requirements.

Writing Use Cases

A use case is a description of how a user interacts with a system to achieve a specific goal. It includes:

Naming a Use Case

Use case names often follow an "actor verb noun" pattern, like "Player Places Bid" or "Customer Adds Item to Cart". If the actor is very general or is known ahead of time, it can be left out.

Preconditions

List the assumptions we make about the use case. For example, "Starting warehouse ID is not null" would be a good precondition for a route planning use case.

Invariants

List the promises you can make about what won't change when the use case is performed. For example, "Input will not be modified".

Postconditions

List the promises you can make about what will change by the time the use case is done. For example, "Result will be the order in which the drone should deliver items such that it travels the shortest distance."

Steps

List the steps that the actor and your software will take. These are most useful if they follow one of these templates:

Notice that none of the steps includes the word "if". Instead of using "if" in a step, create two use cases with preconditions for each of the "if" conditions.

Example Use Case

User Login

Preconditions:

  • User has a valid account
  • User is not already logged in

Steps:

  1. User enters email and password
  2. System validates credentials
  3. System creates session
  4. User is redirected to dashboard

Postconditions:

  • User is logged in
  • Session is created
  • User is on dashboard page

Alternate Cases:

  • Invalid credentials - show error message
  • Account locked - show lockout message
  • Network error - show connection error

Route Planning Example

Requests Shortest Route from Non-null Warehouse ID

Preconditions:

  • The input is a non-null warehouse ID and a list of orders.

Invariants:

  • The input will not be modified.

Postconditions:

  • The result will be a sorted list of orders that provides the shortest delivery route.

Steps:

  1. The caller invokes the shortest route function with an existing warehouse ID and a list of orders.
  2. The algorithm calculates the shortest delivery route and returns the sorted list of orders.

Requests Shortest Route from Null Warehouse ID

Preconditions:

  • The input is a null warehouse ID and a list of orders.

Invariants:

  • The input will not be modified.

Postconditions:

  • The result is an exception.

Steps:

  1. The caller calls the shortest route function with a null warehouse ID and a list of orders.
  2. The function raises an IllegalArgumentException.

Best Practices

Implementing Use Cases in Code

When we write code, we turn "the software" steps in all the use cases into Java. Here's an example implementation for the shortest route use case:

public class ShortestRouteFromWarehouse {
    /**
     * Finds the shortest route from a warehouse to deliver all orders.
     * 
     * @param warehouseId The ID of the starting warehouse
     * @param orders The orders to be delivered
     * @return A sorted list of orders representing the shortest delivery route
     * @throws IllegalArgumentException if warehouseId is null
     */
    public List<Order> findShortestRoute(String warehouseId, List<Order> orders) {
        // Check precondition
        if (warehouseId == null) {
            throw new IllegalArgumentException("Warehouse ID cannot be null");
        }
        
        // Make a copy to ensure we don't modify the input (invariant)
        List<Order> routeOrders = new ArrayList<>(orders);
        
        // Calculate the shortest route (simplified for example)
        Collections.sort(routeOrders, (o1, o2) -> {
            // Sort based on distance from warehouse and between orders
            // Implementation details omitted for brevity
            return 0;
        });
        
        // Return the sorted list (postcondition)
        return routeOrders;
    }
}

Refining the Requirements

Complex software can have many requirements, making it easy to forget or misunderstand important functionality. You can find missed functionality by examining each step of your use cases and asking, "what could go wrong here?" Make a new use case with preconditions for every answer.

Once you're done, determine which requirement each use case helps satisfy. Some requirements will have multiple use cases. Requirements without use cases indicate that you either don't understand how the customer will use your software or need to write another use case.

On the other hand, use cases without requirements indicate that you either have found a hidden requirement or don't need to write that code.

Video Content