Comp 110 Test-Driven Programming: Using Use and Edge Cases

Best Practices when Writing and Testing Functions

STEP 1: Write a "function definition skeleton" meaning:

  1. Declare the function with the correct name, parameter, and return type
  2. Return a "dummy" value to begin with
    1. Return type is number? Return 0.
    2. Return type is string? Return "?".
    3. Return type is boolean? Return false.
    4. Return type is List? Return null.

STEP 2: Create Use Cases

STEP 3: Implement the Logic for the Most Common Cases

STEP 4: Create and Address Edge Cases

Example:

Task: write a function repeatStuff that takes in a string str and a number n and returns a string that repeats n times. If n is negative, return "Oh Bo".

STEP 1: Write a "function definition skeleton" meaning

import { print } from "introcs";

let repeatStuff = (str: string, n: number): string => {

     return "?";
}

STEP 2: Create Use Cases

What are the most common use cases that one would want to use this function for? Add these to your main function, while making note of the "expected" values that should be returned.

import { print } from "introcs";

export let main = async () => {
     print(repeatStuff("Bo", 4)); // -> "BoBoBoBo"
     print(repeatStuff("MakeHappy", 2)); / /-> "MakeHappyMakeHappy"
     print(repeatStuff("what.", 0)); // -> "
};

main();

STEP 3: Implement the Logic for the Most Common Cases

This will vary based on the problem; use the tools you have learned in class to handled the most common use case.

import { print } from "introcs";

export let main = async () => {
     print(repeatStuff("Bo", 4)); // -> "BoBoBoBo"
     print(repeatStuff("MakeHappy", 2)); / /-> "MakeHappyMakeHappy"
     print(repeatStuff("what.", 0)); // -> "
     print(repeatStuff("#Deep", -1)); // -> "Oh Bo"
};

let repeatStuff = (str: string, n: number): string => {
    let finalString = "";
    for (let i = 0; i < n; i++) { // loop n times
        finalString = finalString + str;
        // finalString starts as an empty string
        // for each iteration of the loop, str will be concatenated onto the final string
    }
    return finalString; // return the final concatenated str
};

main();

STEP 4: Create and Address Edge Cases

(When you are sure your use case tests are returning what is expected) In the main function, include the less common 'edge' cases whose logic will differ from the most common use case. Then, work to incorporate this logic into your function.

import { print } from "introcs";

export let main = async () => {
    print("Welcome to COMP110!");
    print(repeatStuff("Bo", 4)); // -> "BoBoBoBo"
    print(repeatStuff("MakeHappy", 2)); // -> "MakeHappyMakeHappy"
    print(repeatStuff("what.", 0)); // -> "
    print(repeatStuff("#Deep", -1)); // -> "Oh Bo"

};



let repeatStuff = (str: string, n: number): string => {
    let finalString = "";
    if (n < 0) {
        return "Oh Bo";
    } else {
        for (let i = 0; i < n; i++) { // loop n times
            finalString = finalString + str;
            // finalString starts as an empty string
            // for each iteration of the loop, str will be concatenated onto the final string
        }
        return finalString; // return the final concatenated str
    }
};
main();