1 Testing in Haskell: using HUnit Notes, thanks to Mark P Jones Portland State University.

Slides:



Advertisements
Similar presentations
Introduction to Unit Testing Svetlin Nakov Telerik Corporation
Advertisements

Extended Static Checking for Haskell (ESC/Haskell) Dana N. Xu University of Cambridge advised by Simon Peyton Jones Microsoft Research, Cambridge.
Logic Programming – Part 2 Lists Backtracking Optimization (via the cut operator) Meta-Circular Interpreters.
Logic Programming – Part 2 Lists Backtracking Optimization (via the cut operator) Meta-Circular Interpreters.
MapReduce: Simplified Data Processing on Large Clusters Cloud Computing Seminar SEECS, NUST By Dr. Zahid Anwar.
0 PROGRAMMING IN HASKELL Chapter 7 - Higher-Order Functions.
Higher-Order Functions Koen Lindström Claessen. What is a “Higher Order” Function? A function which takes another function as a parameter. Examples map.
0 PROGRAMMING IN HASKELL Chapter 4 - Defining Functions.
0 PROGRAMMING IN HASKELL Chapter 6 - Recursive Functions Most of this should be review for you.
0 PROGRAMMING IN HASKELL Chapter 6 - Recursive Functions.
Advanced Programming Andrew Black and Tim Sheard Lecture 4 Intro to Haskell.
Writing a Unit test Using JUnit At the top of the file include: import junit.framework.TestCase; The main class of the file must be: public Must extend.
Advanced Programming Andrew Black and Tim Sheard Lecture 6 Regular Expressions Unit Testing.
Comp 205: Comparative Programming Languages Functional Programming Languages: More Lists Recursive definitions List comprehensions Lecture notes, exercises,
Unit Testing & Defensive Programming. F-22 Raptor Fighter.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
Abstraction IS 101Y/CMSC 101 Computational Thinking and Design Tuesday, September 17, 2013 Carolyn Seaman University of Maryland, Baltimore County.
CPSC 252 Exception Handling Page 1 Exceptions and exception handling Client programmers can make errors using a class attempting to dequeue an item from.
WEEK EXCEPTION HANDLING. Syntax Errors Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint you get while.
Computer Science and Engineering College of Engineering The Ohio State University JUnit The credit for these slides goes to Professor Paul Sivilotti at.
Functional Programming in Haskell Motivation through Concrete Examples Adapted from Lectures by Simon Thompson.
Chapter 9 Defining New Types. Objectives Explore the use of member functions when creating a struct. Introduce some of the concepts behind object-oriented.
SDD/DFS L.K.Lundin VLT 2 nd Generation Instrumentation Pipelines, 19 Apr Pipeline Test methods Lars Kr. Lundin - CPL developer - NACO and VISIR.
0 PROGRAMMING IN HASKELL Chapter 7 - Defining Functions, List Comprehensions.
Abstraction IS 101Y/CMSC 101 Computational Thinking and Design Tuesday, September 17, 2013 Marie desJardins University of Maryland, Baltimore County.
Chapter 13 Recursion. Learning Objectives Recursive void Functions – Tracing recursive calls – Infinite recursion, overflows Recursive Functions that.
Advanced Functional Programming 2009 Ulf Norell (lecture by Jean-Philippe Bernardy)
Sound Haskell Dana N. Xu University of Cambridge Joint work with Simon Peyton Jones Microsoft Research Cambridge Koen Claessen Chalmers University of Technology.
A Second Look At ML 1. Outline Patterns Local variable definitions A sorting example 2.
Overview of the Haskell 98 Programming Language
© M. Winter COSC 4P41 – Functional Programming Modules in Haskell Using modules to structure a large program has a number of advantages: Parts of.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Haskell: Higher-order Functions Dr. Hyunyoung Lee.
Scientific Debugging. Errors in Software Errors are unexpected behaviors or outputs in programs As long as software is developed by humans, it will contain.
1 CS 457/557: Functional Languages Lists and Algebraic Datatypes Mark P Jones Portland State University.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Interactive Programs: I/O and Monads Dr. Hyunyoung Lee.
Function Definition by Cases and Recursion Lecture 2, Programmeringsteknik del A.
First Order Haskell Neil Mitchell York University λ.
Recursion on Lists Lecture 5, Programmeringsteknik del A.
Kyung-Goo Doh Hanyang University - ERICAComputer Science & Engineering Functional Programming / Imperative Programming CSE215 Fundamentals of Program Design.
0 PROGRAMMING IN HASKELL Chapter 4 - Defining Functions.
Case Study: Route Finding Lecture 6, Programmeringsteknik del A.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Haskell: More on Functions and List Comprehensions Dr. Hyunyoung Lee.
Chapter SevenModern Programming Languages1 A Second Look At ML.
CSE 311 Foundations of Computing I Lecture 28 Computability: Other Undecidable Problems Autumn 2011 CSE 3111.
1 Static Contract Checking for Haskell Dana N. Xu University of Cambridge Joint work with Simon Peyton Jones Microsoft Research Cambridge Koen Claessen.
0 PROGRAMMING IN HASKELL Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and a few other sources) Odds and Ends,
Guards1. 2 Let’s test this function. Main> maxi Here is a trace of the function: n m maxi 3 2 Guards or conditions are used to express various cases.
Unit Testing with FlexUnit
Recursion Higher Order Functions CSCE 314 Spring 2016.
Haskell Chapter 4. Recursion  Like other languages  Base case  Recursive call  Author programs a number of built-in functions as examples.
Functional Programming Lecture 3 - Lists Muffy Calder.
Haskell Chapter 5, Part II. Topics  Review/More Higher Order Functions  Lambda functions  Folds.
List Operations CSCE 314 Spring CSCE 314 – Programming Studio Tuple and List Patterns Pattern matching with wildcards for tuples fst (a, _) = a.
CS321 Functional Programming 2 © JAS Programming with Streams A stream is never finite and could be defined as special polymorphic type data stream.
FILES AND EXCEPTIONS Topics Introduction to File Input and Output Using Loops to Process Files Processing Records Exceptions.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
Advanced Functional Programming 2010
Conditional Expressions
Software Testing An Introduction.
Haskell Chapter 4.
PROGRAMMING IN HASKELL
Higher-Order Functions
Debugging Haskell by Observing Intermediate Data Structures
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
CSCE 314: Programming Languages Dr. Dylan Shell
PROGRAMMING IN HASKELL
Programming Languages
PROGRAMMING IN HASKELL
Presentation transcript:

1 Testing in Haskell: using HUnit Notes, thanks to Mark P Jones Portland State University

2 Testing, Testing, Testing, …

3 Testing: Testing can confirm expectations about how things work Conversely, testing can set expectations about how things should work It can be dangerous to generalize from tests “Testing can be used to show the presence of bugs, but never to show their absence” [Edsger Dijkstra, 1969] But testing does help us to find & avoid: Bugs in the things we build Bugs in the claims we make about those things

4 Example: filter filter :: (a -> Bool) -> [a] -> [a] filter even [1..10] = [2,4,6,8,10] filter (<5) [1..100] = [1,2,3,4] filter (<5) [100,99..1] = [4,3,2,1]

5 Making Tests Executable: test1 = filter even [1..10] == [2,4,6,8,10] test2 = filter (<5) [1..100] == [1,2,3,4] test3 = filter (<5) [100,99..1] == [4,3,2,1]

6 Making Tests Executable: test1 = filter even [1..10] == [2,4,6,8,10] test2 = filter (<5) [1..100] == [1,2,3,4] test3 = filter (<5) [100,99..1] == [4,3,2,1] tests= test1 && test2 && test3

7 Pros: Tests are simple functional programs Tests are self-checking Cons: Have to run tests manually Testing stops as soon as one test fails No indication of which test failed No summary statistics (e.g., # tests run) Harder to handle complex behavior (e.g., testing code that performs I/O actions, raises an exception, …)

8 Unit Testing in Haskell

9 Enter HUnit: A library for unit testing Written in Haskell Available from (Or from Built-in to recent versions of Hugs and GHC Just “import Test.HUnit” and you’re ready!

10 Defining Tests: import Test.HUnit test1 = TestCase (assertEqual "filter even [1..10]" (filter even [1..10]) [2,4,6,8,10]) test2= … test3= … tests= TestList [test1, test2, test3]

11 Running Tests: Main> runTestTT tests Cases: 3 Tried: 3 Errors: 0 Failures: 0 Main>

12 Detecting Faults: import Test.HUnit test1 = TestCase (assertEqual “filter even [1..10]” (filter even [1..10]) [2,4,6,9,10]) test2= … test3= … tests= TestList [test1, test2, test3]

13 Using HUnit: Main> runTestTT tests ### Failure in: 0 filter even [1..10] expected: [2,4,6,8,10] but got: [2,4,6,9,10] Cases: 3 Tried: 3 Errors: 0 Failures: 1 Main>

14 Labeling Tests: … tests= TestLabel “filter tests” $ TestList [test1, test2, test3]

15 Using HUnit: Main> runTestTT tests ### Failure in: filter tests:0 filter even [1..10] expected: [2,4,6,8,10] but got: [2,4,6,9,10] Cases: 3 Tried: 3 Errors: 0 Failures: 1 Main>

16 The Test and Assertion Types: data Test= TestCase Assertion | TestList [Test] | TestLabel String Test runTestTT:: Test -> IO Counts assertFailure :: String -> Assertion assertBool:: String -> Bool -> Assertion assertEqual:: (Eq a, Show a) => String -> a -> a -> Assertion

17 Problems: Finding and running tests is a manual process (easily skipped/overlooked) It can be hard to trim tests from distributed code We still can’t solve the halting problem

18 Example: merge Let’s develop a merge function for combining two sorted lists into a single sorted list: merge :: [Int] -> [Int] -> [Int] merge = undefined What about test cases?

19 Merge Tests: Simple examples: merge [1,5,9] [2,3,6,10] == [1,2,3,5,6,9,10] One or both arguments empty: merge [] [1,2,3] == [1,2,3] merge [1,2,3] [] == [1,2,3] Duplicate elements: merge [2] [1,2,3] == [1,2,3] merge [1,2,3] [2] == [1,2,3]

20 Capturing the Tests: mergeTests = TestLabel "merge tests” $ TestList [simpleTests, emptyTests, dupTests] simpleTests = TestLabel "simple tests” $ TestCase (assertEqual "merge [1,5,9] [2,3,6,10]" (merge [1,5,9] [2,3,6,10]) [1,2,3,5,6,9,10]) emptyTests = …

21 Capturing the Tests: Main> runTestTT mergeTests Cases: 6 Tried: 0 Errors: 0 Failures: 0 Program error: Prelude.undefined Main>

22 Refining the Definition (1): Let’s provide a little more definition for merge: merge :: [Int] -> [Int] -> [Int] merge xs ys = [] What happens to the test cases now?

23 Back to the Tests: Main> runTestTT mergeTests ### Failure in: merge tests:0:simple tests merge [1,5,9] [2,3,6,10] expected: [] but got: [1,2,3,5,6,9,10] … Cases: 6 Tried: 6 Errors: 0 Failures: 5 Main>

24 Refining the Definition (2): Let’s provide a little more definition for merge: merge :: [Int] -> [Int] -> [Int] merge xs ys = xs What happens to the test cases now?

25 Back to the Tests: Main> runTestTT mergeTests ### Failure in: merge tests:0:simple tests merge [1,5,9] [2,3,6,10] expected: [1,5,9] but got: [1,2,3,5,6,9,10] ### Failure in: merge tests:2:duplicate elements:0 merge [2] [1,2,3] expected: [2] but got: [1,2,3] Cases: 6 Tried: 6 Errors: 0 Failures: 2 Main>

26 Refining the Definition (3): Use type information to break the definition down into multiple cases: merge :: [Int] -> [Int] -> [Int] merge [] ys = ys merge (x:xs) ys = ys

27 Refining the Definition (4): Repeat … merge :: [Int] -> [Int] -> [Int] merge [] ys = ys merge (x:xs) [] = x:xs merge (x:xs) (y:ys) = x:xs

28 Refining the Definition (5): Use guards to split into cases: merge :: [Int] -> [Int] -> [Int] merge [] ys = ys merge (x:xs) [] = x:xs merge (x:xs) (y:ys) | x<y = x : merge xs (y:ys) | otherwise = y : merge (x:xs) ys

29 Back to the Tests: Main> runTestTT mergeTests ### Failure in: merge tests:2:duplicate elements:0 merge [2] [1,2,3] expected: [1,2,2,3] but got: [1,2,3] ### Failure in: merge tests:2:duplicate elements:1 merge [1,2,3] [2] expected: [1,2,2,3] but got: [1,2,3] Cases: 6 Tried: 6 Errors: 0 Failures: 2 Main>

30 Refining the Definition (6): Use another guards to add another case: merge :: [Int] -> [Int] -> [Int] merge [] ys = ys merge (x:xs) [] = x:xs merge (x:xs) (y:ys) | x<y = x : merge xs (y:ys) | y<x = y : merge (x:xs) ys | x==y = x : merge xs ys

31 Back to the Tests: Main> runTestTT mergeTests Cases: 6 Tried: 6 Errors: 0 Failures: 0 Main>

32 Modifying the Definition: Suppose we decide to modify the definition: merge :: [Int] -> [Int] -> [Int] merge (x:xs) (y:ys) | x<y = x : merge xs (y:ys) | y<x = y : merge (x:xs) ys | x==y = x : merge xs ys merge xs ys = xs ++ ys Is this still a valid definition?

33 Back to the Tests: Main> runTestTT mergeTests Cases: 6 Tried: 6 Errors: 0 Failures: 0 Main>

34 Lessons Learned: Writing tests (even before we’ve written the code we want to test) can expose key details / design decisions A library like HUnit can help to automate the process (at least partially) Development alternates between coding and testing Bugs are expensive, running tests is cheap Good tests can last a long time; continuing use as code evolves