Functional Problem Solving (CSC 151 2016S) : Labs
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] - [FAQ] [Teaching & Learning] [Grading] [Taking Notes] [Rubric]
Current: [Assignment] [EBoard] [Lab] [Outline] [Reading]
Sections: [Assignments] [EBoards] [Labs] [Outlines] [Readings] - [Examples] [Handouts]
Reference: [Setup] [Remote] [VM] [Errors] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Curtsinger (2016S)] [Davis (2013F)] [Rebelsky (2015F)] [Weinman (2014F)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] - [Issue Tracker (Course)]
Summary: In the laboratory, you will explore the ways in which small tests can help you develop and update code. You will also familiarize yourself with the RackUnit unit testing library.
a. After starting DrRacket, add (require gigls/unsafe),
(require rackunit) and
(require rackunit/text-ui) to your definitions pane and
click .
b. Read the following procedures to make sure that you understand what they do, and then add the code to your definitions pane.
;;; Procedure:
;;; drawing-center-x
;;; Parameters:
;;; drawing, a drawing
;;; Purpose:
;;; Get the x coordinate of the center of a drawing
;;; Produces:
;;; x, a real number
;;; Preconditions:
;;; drawing has positive width and height.
;;; Postconditions:
;;; (- (drawing-right drawing) x) is approximately (- x (drawing-left drawing))
(define drawing-center-x
(lambda (drawing)
(+ (drawing-left drawing) (* 1/2 (drawing-width drawing)))))
;;; Procedure:
;;; drawing-center-y
;;; Parameters:
;;; drawing, a drawing
;;; Purpose:
;;; Get the y coordinate of the center of a drawing
;;; Produces:
;;; y, a real number
;;; Preconditions:
;;; drawing has positive width and height.
;;; Postconditions:
;;; (- (drawing-bottom drawing) y) is approximately (- y (drawing-top drawing))
(define drawing-center-y
(lambda (drawing)
(+ (drawing-top drawing) (* 1/2 (drawing-height drawing)))))
c. Suppose we are going to have to work with a drawing called
(, which is supposed to make
a copy of center-at
drawing x
y)drawing, centered at the
point (x,y).
Sketch the postconditions for that procedure.
Traditionally, we might “test” an implementation of this procedure by rendering some drawings centered at various positions. For example, here is some code that students might have written.
> (image-show (drawing->image (center-at (drawing-scale drawing-unit-square 50)
50 50)
100 100))
> (image-show (drawing->image (center-at (drawing-scale drawing-unit-square 30)
70 70)
100 100))
They would then “eyeball” the images to make sure that they are in the right location. The first should be centered at (50,50), the second should be centered at (70,70).
What potential flaws do you see in their testing process?
To avoid some of the flaws you may have noted in the prior approach, many programmers express their tests using a framework like Rackunit. Doing so allows them to automatically check results without having to spend the effort of looking at them by hand.
Here is a simple test suite based on the prior experiments.
(define test-center-at
(test-suite
"Tests of center-at"
(test-case
"Example One"
(check-= (drawing-center-x (center-at (scale-drawing 50 drawing-unit-square)
50 50))
50
1)
(check-= (drawing-center-y (center-at (scale-drawing 50 drawing-unit-square)
50 50))
50
1))
(test-case
"Example Two"
(check-= (drawing-center-x (center-at (scale-drawing 30 drawing-unit-square)
70 70))
70
1)
(check-= (drawing-center-y (center-at (scale-drawing 30 drawing-unit-square)
70 70))
70
1))))
Note that the “1” that is the last parameter to each call
to check-= says that we will accept an answer that
is within one unit of the expected point. As you've seen in your
work with drawings, many computations are unavoidably off by one
pixel, and so we have accommodated for that issue.
a. What do you see as advantages or disadvantages of this approach as compared to one from the previous exercise?
b. Think about (but do not add) any additional tests that you think might be useful.
Here is an implementation of center-at.
(define center-at
(lambda (drawing x y)
(vshift-drawing x (hshift-drawing y drawing))))
a. Does it seem to be correct? Why or why not?
b. Do you expect it to pass the test suite we designed?
c. Run the test suite to see whether or not it passes. You can use the following command.
> (run-tests test-center-at)
d. Unfortunately, it's an incorrect implementation because it
shifts vertically by x and shifts horizontally
by y rather than x.
Hence, we should extend our test suite. Write additional tests that
would identify that problem.
Here is a revised implementation of center-at.
(define center-at
(lambda (drawing x y)
(vshift-drawing y (hshift-drawing x drawing))))
a. Does it seem to be correct? Why or why not?
b. Do you expect it to pass the revised test suite?
c. Run the test suite to see whether or not it passes.
d. As you may have observed, this implementation will not work correclty for a drawing that is not originally centered on the origin. If this version passes your test suite, add additional tests that identify that problem.
Here is an even more revised implementation of
center-at.
(define center-at
(lambda (drawing x y)
(vshift-drawing
(abs (- y (drawing-center-y drawing)))
(hshift-drawing
(abs (- x (drawing-center-x drawing)))
drawing))))
a. Does it seem to be correct? Why or why not?
b. Do you expect it to pass the revised test suite?
c. Run the test suite to see whether or not it passes.
d. As you may have observed, this implementation will not work correclty for a drawing that must be shifted left or up. If this version passes your test suite, add additional tests that identify that problem.
Here is a revised implementation of center-at
that is intended to fix the problems observed above.
(define center-at
(lambda (drawing x y)
(vshift-drawing
y
(hshift-drawing
x
drawing-unit-square))))
a. Does it seem to be correct? Why or why not?
b. Do you expect it to pass the revised test suite?
c. Run the test suite to see whether or not it passes.
d. As you may have observed, this implementation makes a square, rather than using the original drawing. We can tell that it's incorrect because the result has the wrong width and height. But many test suites don't check the width and height. If this version passes your test suite, add additional tests that identify that problem.
The revisions continue!
(define center-at
(lambda (drawing x y)
(vshift-drawing
y
(hshift-drawing
x
(hscale-drawing
(drawing-width drawing)
(vscale-drawing
(drawing-height drawing)
drawing-unit-square))))))
a. Does it seem to be correct? Why or why not?
b. Do you expect it to pass the revised test suite?
c. Run the test suite to see whether or not it passes.
d. As you may have observed, this implementation will not work
correclty for a drawing that is not originally centered on the
origin. If this version passes your test suite, add additional
tests that identify that problem. Note that the
drawing-type method returns a value that indicates
the type of drawing (ellipse, rectangle, or group).
Add any other tests that you think will be useful.
At the beginning of this lab, you sketched postconditions for the
center-at method. You have now thought more
carefully about that procedure. Write postconditions for
center-at. You should refer to the shifted
drawing as “result”.
Consider the following procedure and procedure call.
(define check-recentered-drawing
(lambda (original modified x y)
(check-= (drawing-center-x modified) x 1)
(check-= (drawing-center-y modified) y 1)
(check-= (drawing-width modified) (drawing-width original) .001)
(check-= (drawing-height modified) (drawing-height original) .001)
(check-equal? (drawing-color modified) (drawing-color original))
(check-equal? (drawing-type modified) (drawing-type original))))
> (define shape1
(drawing-hshift 11
(drawing-vshift 12
(drawing-scale 10
drawing-unit-circle))))
> (test-case
"shape1 at (17.2, -230/11)"
(check-recentered-drawing shape1 (center-at shape1 17.2 -230/11) 17.2 -230/11))
Why might a programmer choose to include such a procedure in zir test programs?
Here's another helper procedure.
(define crd
(lambda (drawing x y)
(check-recentered-drawing drawing (center-at drawing x y) x y)))
Why might a programmer include this procedure in zir code?
Make as comprehensive a list as possible of things you would want to test.