STEP 1: Write a "function definition skeleton," meaning:
STEP 2: Create Use Cases
1. What are some usual input parameters?
- These are called use cases.They represent how the function will used most of the time.
2. What are some valid but unusual input parameters?
- These are your edge cases.They represent the weird uncommon cases that we still want to account for.
3. Given those input parameters, what is your expected return value for each set of inputs?
STEP 3: Implement the Logic for the Most Common Cases, run your test cases!
STEP 4: Create and Address Edge Cases, run your test cases again!
Repeat steps 3 & 4 with more cases until you are confident your code works!
Another example of this process in action can be found in Test Functions.
Task: write a function repeatStuff that takes in a string str and a number n and returns a array of strings that repeats 'str' '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 { testArray } from "./test-util";
export let main = async () => {
testString("Bo string", "BoBoBoBo", repeatStuff("Bo", 4)); // we expect the result of our function call to be "BoBoBoBo"
testString("MakeHappy string", "MakeHappyMakeHappy", repeatStuff("MakeHappy", 2));
testString("Repeat 0 times", "", repeatStuff("what.", 0)); // -> "
// before you write your function logic, these tests will appear in the browser as failures
};
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 { testArray } from "./test-util";
export let main = async () => {
testArray("Bo string", ["Bo", "Bo", "Bo," "Bo"], repeatStuff("Bo", 4));
testArray("MakeHappy string", ["MakeHappy", "MakeHappy"], repeatStuff("MakeHappy", 2));
};
let repeatStuff = (str: string, n: number): string[] => {
let finalArray = [];
for (let i = 0; i < n; i++) { // loop n times
finalArray[finalArray.length] = str;
// finalArray starts as an empty array
// for each iteration of the loop, str will be appended to the end of the array
}
return finalArray;
};
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 { testArray } from "./test-util";
export let main = async () => {
testArray("Bo string", ["Bo", "Bo", "Bo," "Bo"], repeatStuff("Bo", 4));
testArray("MakeHappy string", ["MakeHappy", "MakeHappy"], repeatStuff("MakeHappy", 2));
testArray("Repeat 0 times", [], repeatStuff("what.", 0));
testArray("Repeat negative number", [], repeatStuff("#Deep", -1));
};
let repeatStuff = (str: string, n: number): string[] => {
if (n < 0) { // this takes care of our edge case!
return [];
} else {
let finalArray = [];
for (let i = 0; i < n; i++) {
finalArray[finalArray.length] = str;
}
return finalString;
};
main();