Unit Testing.

Slides:



Advertisements
Similar presentations
Selection Control Structures Chapter 5: Selection Asserting Java © Rick Mercer.
Advertisements

Annoucements  Next labs 9 and 10 are paired for everyone. So don’t miss the lab.  There is a review session for the quiz on Monday, November 4, at 8:00.
String and Lists Dr. Benito Mendoza. 2 Outline What is a string String operations Traversing strings String slices What is a list Traversing a list List.
Insertion sort, Merge sort COMP171 Fall Sorting I / Slide 2 Insertion sort 1) Initially p = 1 2) Let the first p elements be sorted. 3) Insert the.
Recursion. Objectives At the conclusion of this lesson, students should be able to Explain what recursion is Design and write functions that use recursion.
Understanding class definitions Looking inside classes.
Sorting and Searching Arrays CSC 1401: Introduction to Programming with Java Week 12 – Lectures 1 & 2 Wanda M. Kunkle.
Recursion.
Building Java Programs Chapter 13 Searching reading: 13.3.
SEARCHING, SORTING, AND ASYMPTOTIC COMPLEXITY Lecture 12 CS2110 – Fall 2009.
Chapter 11Java: an Introduction to Computer Science & Programming - Walter Savitch 1 Chapter 11 l Basics of Recursion l Programming with Recursion Recursion.
Data Structures & Algorithms CHAPTER 4 Searching Ms. Manal Al-Asmari.
Searching. Linear (Sequential) Search Search an array or list by checking items one at a time. Linear search is usually very simple to implement, and.
BINARY SEARCH CS16: Introduction to Data Structures & Algorithms Thursday February 12,
Sorting Algorithms. Sorting Sorting is a process that organizes a collection of data into either ascending or descending order. public interface ISort.
Chapter 15 Running Time Analysis. Topics Orders of Magnitude and Big-Oh Notation Running Time Analysis of Algorithms –Counting Statements –Evaluating.
String and Lists Dr. José M. Reyes Álamo. 2 Outline What is a string String operations Traversing strings String slices What is a list Traversing a list.
Lesson 3 Functions. Lesson 3 Functions are declared with function. For example, to calculate the cube of a number function function name (parameters)
Arrays Chapter 7.
Hubert Chan (Chapters 1.6, 1.7, 4.1)
Searching Arrays Linear search Binary search small arrays
Searching and Sorting Searching algorithms with simple arrays
Operator Overloading Introduction
Using recursion for Searching and Sorting
Fundamentals of Algorithms MCS - 2 Lecture # 11
Definition of the Programming Language CPRL
Recursion Version 1.0.
Pseudo-code 1 Running time of algorithm is O(n)
Searching.
CIS3931 – Intro to JAVA Lecture Note Set 2 17-May-05.
COP 3503 FALL 2012 Shayan Javed Lecture 15
Instructor: Craig Duckett Lecture 09: Tuesday, April 25th, 2017
Chapter 9: Searching, Sorting, and Algorithm Analysis
Arrays 2/4 By Pius Nyaanga.
GC211Data Structure Lecture2 Sara Alhajjam.
Testing UW CSE 160 Winter 2017.
Debugging and Random Numbers
Reasoning About Code.
Reasoning about code CSE 331 University of Washington.
JavaScript Syntax and Semantics
Algorithm Analysis CSE 2011 Winter September 2018.
Hubert Chan (Chapters 1.6, 1.7, 4.1)
An Introduction to Java – Part I
Testing UW CSE 160 Spring 2018.
Adapted from Pearson Education, Inc.
Conditions and Ifs BIS1523 – Lecture 8.
Testing UW CSE 160 Winter 2016.
searching Concept: Linear search Binary search
Searching and Sorting Arrays
Object Oriented Programming in java
String and Lists Dr. José M. Reyes Álamo.
Logical Operations In Matlab.
CSE 373 Data Structures and Algorithms
Binary Search Trees A special case of a Binary Tree
Searching, Sorting, and Asymptotic Complexity
COMPUTER 2430 Object Oriented Programming and Data Structures I
Basics of Recursion Programming with Recursion
Chapter 6 Arrays.
Searching.
Suggested self-checks: Section 7.11 #1-11
Discrete Mathematics and its Applications
CSE 143 Lecture 2 ArrayIntList, binary search
Assertions References: internet notes; Bertrand Meyer, Object-Oriented Software Construction; 4/25/2019.
An Overview of C.
Arrays Wellesley College CS230 Lecture 02 Thursday, February 1
First Semester Review.
Java Coding 6 David Davenport Computer Eng. Dept.,
Sorting Algorithms.
Programming Methodology
Reasoning with Types.
Presentation transcript:

Unit Testing

Our First Program: Binary Search Problem Statement: Write a function that consumes (1) a number to search for, and (2) an array of numbers sorted in ascending order. The function should produce true if the array contains the number and false if it does not. Examples: search(5, [2, 5]) // produces true search(4, [2, 5]) // produces false search(7, [2, 5, 7]) // produces true Type Signature: // search(v: number, a: number[]): boolean function search(v, a) { // TODO } function name argument name and type result type You should write the type of functions in a comment. It helps plan your code.

Step 1: Recursive pattern // search(v: number, a: number[]): boolean function search(v, a) { // Since the length of the array is unknown, // we will recur on the length of a. if (a.length === 0) { // FILL } else { }

Step 2: Fill in base-case // search(v: number, a: number[]): boolean function search(v, a) { // Since the length of the array is unknown, // we will recur on the length of a. if (a.length === 0) { return false; } else { // FILL } If the length of the array is 0, then there are no values in the array.

Step 4: Compare v to the middle element // search(v: number, a: number[]): boolean function search(v, a) { // Since the length of the array is unknown, // we will recur on the length of a. if (a.length === 0) { return false; } else { let mid = a.length / 2; if (a[mid] === v) { return true; } else if (a[mid] > v) { // FILL } else /* a[mid] < v */ { } Three cases: the value in the middle is equal

Step 5: Fill in recursive cases // search(v: number, a: number[]): boolean function search(v, a) { // Since the length of the array is unknown, // we will recur on the length of a. if (a.length === 0) { return false; } else { let mid = a.length / 2; if (a[mid] === v) { return true; } else if (a[mid] > v) { return search(v, a.slice(0, mid)); } else /* a[mid] < v */ { return search(v, a.slice(mid + 1, a.length)); } Note: a.slice method

Testing // search(v: number, a: number[]): boolean function search(v, a) { // Since the length of the array is unknown, // we will recur on the length of a. if (a.length === 0) { return false; } else { let mid = a.length / 2; if (a[mid] === v) { return true; } else if (a[mid] > v) { return search(v, a.slice(0, mid)); } else /* a[mid] < v */ { return search(v, a.slice(mid + 1, a.length)); } Do both these test cases work? search(5, [2, 5]) search(5, [2, 5, 8]) JavaScript does not have integer division: > 3 / 2 1.5

Bug fix // search(v: number, a: number[]): boolean function search(v, a) { // Since the length of the array is unknown, // we will recur on the length of a. if (a.length === 0) { return false; } else { let mid = Math.floor(a.length / 2); if (a[mid] === v) { return true; } else if (a[mid] > v) { return search(v, a.slice(0, mid)); } else /* a[mid] < v */ { return search(v, a.slice(mid + 1, a.length)); } These tests now work search(5, [2, 5]) search(5, [2, 5, 8]) Should we write more tests? Why not? More is better, right? Better question: do our tests cover all cases?

Test Coverage // search(v: number, a: number[]): boolean function search(v, a) { // Since the length of the array is unknown, // we will recur on the length of a. if (a.length === 0) { return false; } else { let mid = Math.floor(a.length / 2); if (a[mid] === v) { return true; } else if (a[mid] > v) { } else /* a[mid] < v */ { } This implementation is obvious broken. But, these tests still work. search(5, [2, 5]) search(5, [2, 5, 8]) The problem is that the wrong lines of code are not executed. Think of length-3 arrays that: Execute the wrong lines and pass. These tests are not informative. Execute the wrong lines and fail. These tests are informative and reveal actual bugs. search(5, [1, 2, 3]); search(5, [1, 2, 5]);

(Some) Lessons About Testing May need multiple test cases Question: How many? Tests should check execution in all branches of code This is called test coverage Tests should be informative Not executing the intended branches of code leads to incorrect results

Testing with Ocelot Name of the test Body of the test test("Empty list", function() { let a = []; assert(search(1, a) === false); }); test("Mid match", function() { let a = [1, 4, 5]; assert(search(4, a) === true); test("Search upper half", function() { assert(search(5, a) === true); assert(search(4.5, a) === false); assert(search(7, a) === false); Name of the test Body of the test This is an anonymous function. We will study them in detail very soon. Assertions succeed only if provided a boolean expression that is true Can have multiple assertions

Mini-Program: Comparing Arrays Problem Statement: Write a function that consumes two arrays of numbers. The function should produce true if the arrays have exactly the same values in-order, and otherwise false. Examples: arrayEqual([1, 2], [1, 2]) // produces true arrayEqual([1, 2], [2, 1]) // produces false arrayEqual([1, 2], [1, 2, 3]) // produces false Type Signature: // arrayEqual(a1: number[], a2: number[]): boolean function arrayEqual(a1, a2) { // TODO }

Mini-Program: Comparing Arrays This will not work: // arrayEqual(a1: number[], a2: number[]): boolean function arrayEqual(a1, a2) { return a1 === a2; } Why? It compares references to the arrays, rather than the contents of the arrays. We will explore this in detail in lecture 7. Q: What properties should two arrays have, to declare that they are “equal”?

Mini-Program: Comparing Arrays // arrayEqual(a1: number[], a2: number[]): boolean function arrayEqual(a1, a2) { if (a1.length !== a2.length) { return false; } for (let i = 0; i< a1.length; ++i) { if (a1[i] !== a2[i]) { return true; Q: What cases should we use to test this?

Mini-Program: Comparing Arrays test("empty arrays", function() { assert(arrayEqual([], []) == true); }); test("unequal lengths", function() { assert(arrayEqual([1, 2], [1, 2, 3]) == false); assert(arrayEqual([2, 3], [1, 2, 3]) == false); test("equal lengths", function() { assert(arrayEqual([1, 2], [1, 2]) == true); assert(arrayEqual([1, 2], [2, 3]) == false);

Mini-Program: rootMagnitude Problem Statement: Write a function that consumes an array of numbers and produces an array of numbers. Each element of the output array should be the square-root of the corresponding element in the output array, but with the same sign. Examples: Warning: Math.sqrt produces NaN when applied to a negative number! rootMagnitude([4, 9]) // produces [2, 3] rootMagnitude([0.16, 2.56]) // [0.4, 1.6] rootMagnitude([-16, -25, -100]) // [-4, -5, -10] rootMagnitude([4, -9]) // [2, -3] Type Signature: // rootMagnitude(a: number[]): number[] function rootMagnitude(a1, a2) { // TODO }

Attempt 1: update the array in-place // rootMagnitude(a: number[]): number[] function rootMagnitude(a) { for (let i = 0; i < a.length; ++i) { if (a[i] >= 0) { a[i] = Math.sqrt(a[i]); } else { // TODO } return a; test("Test rootMagnitude", function() { assert(arrayEqual(rootMagnitude([4, 9]), [2, 3])); assert(arrayEqual(rootMagnitude([16, 100]), [4, 10])); }); We need a test case to execute this branch. Updating the array in Note: We use arrayEqual to compare the arrays.

Attempt 1: update the array in-place // rootMagnitude(a: number[]): number[] function rootMagnitude(a) { for (let i = 0; i < a.length; ++i) { if (a[i] >= 0) { a[i] = Math.sqrt(a[i]); } else { a[i] = a[i]; } return a; test("negative elements", function() { assert(arrayEqual(rootMagnitude([4, -1]), [2, -1])); }); The test passes! But, the implementation in obviously wrong. Updating the array in The problem is we are updating the array in-place, so the input and output are identically. Rule of thumb: do not update arrays in-place

Attempt 2: produce a new array // rootMagnitude(a: number[]): number[] function rootMagnitude(a) { let b = []; for (let i = 0; i < a.length; ++i) { if (a[i] >= 0) { b.push(Math.sqrt(a[i])); } else { b.push(-Math.sqrt(-a[i])); } return b; test("negative elements", function() { assert(arrayEqual(rootMagnitude([4, -1]), [2, -1])); }); Note: .push method of arrays adds an element to the end. Arrays in JavaScript are similar to ArrayLists in Java. Updating the array in

(Some) Lessons About Testing May need multiple test cases Question: How many? Tests should check execution in all branches of code This is called test coverage Tests should be informative Not executing the intended branches of code leads to incorrect results Tests may need additional test infrastructure e.g. arrayEqual()