---
# System prepended metadata

title: Pyret Testing Design and Clarity Guide

---

# Pyret Testing Design and Clarity Guide
## Examples
1. All functions, including helper functions, require examples. The only exception is if a function returns an Image. Examples are written in `where`-blocks.
2. Examples should generally be written *before* you start writing your function. Writing good examples will help you understand how your function should behave on different inputs.
3. Examples should reflect various input scenarios so that you exercise the possible behaviors of your function. You do not need to test every input or every input combination (indeed, there are usually infinite possible combinations!), but you should have enough to cover a wide range of your function’s possible behaviors.
4. In particular, your examples should cover *edge cases*–inputs at the boundaries of particular ranges. For instance, many functions that have a number as an input should include an example where that input is `0`.

As an example, let’s consider a function `compare` that takes two numerical inputs `x` and `y` and returns a string. It should return `"way less"` if `x` is smaller than `y - 2`, `"about the same"` if `x` is between `y - 2` and `y + 2` (inclusive) and `"way more"` if `x` is greater than `y + 2`. Here’s a set of good examples for this function.

```=
fun compare(x :: Number, y :: Number) -> String:
  doc: "decribe the relationship between input numbers x and y"
  ... # function body elided
where:
  compare(1, 40) is "way less"
  compare(0, 3) is "way less"
  compare(8, 10) is "about the same"
  compare(1, 1) is "about the same"
  compare(0, 1) is "about the same"
  compare(17, 20) is "way more"
end
```

Notice that these examples cover each interesting “case” of the program. They also include edge cases testing the boundaries–for instance, `compare(8, 10)` is an edge case, since it’s at the boundary between the `"way less"` and `"about the same"` cases.

For most assignments, you can get a substantial amount of partial credit if you write good examples for a function even if your function doesn’t work correctly.

When writing examples before implementing a function, it may be helpful to include because clauses as a way of figuring out what the function body could look like:

```=
fun times-four(x :: Number) -> Number:
  doc: "multiplies input x by four"
  ... # function body elided
where:
  times-four(3) is 12 because 3 * 4
  times-four(0) is 0 because 0 * 4
  times-four(-1) is -4 because -1 * 4
end
```

Unless an assignment says otherwise, `because` clauses are not required–but they might be useful to you!

## Tests
For some assignments, we will ask you to write test cases as well as examples. Test cases are written in `check blocks`. Test cases are generally written after you develop your function and believe it works, in order to gain more confidence in its correctness. Test cases should include inputs that might not have been included in examples–for instance, strings with unusual characters, or fractions.

We will sometimes ask you to write test cases for functions you aren’t actually writing in order to practice writing good tests.

Here’s an example of a function with both examples and test cases:

```=
fun abs-val(x :: Number) -> Number:
  doc: "return the (positive) absolute value of input x"
  ... # function body elided
where:
  abs-val(-4) is 4
  abs-val(0) is 0 # edge case!
  abs-val(3) is 3
end

check:
  abs-val(1908737) is 1908737 # a very large number
  abs-val(-3498347) is 3498347 # a very large negative number
  abs-val(22/7) is 22/7 # a fraction
  abs-val(-0.8) is -0.8 # a negative decimal number
end
```

A handin with this work would receive full testing points.

## Design
1. Use constants to capture relationships between values. For example, if you have `rectangle(500, 300, "solid", "green")` but mean for the height to be a scaled fraction of the width, you should instead write:

```=
width = 500
rectangle(width, 3/5 * width, "solid", "green")
```

2. Use helper functions to configure an expression that appears multiple times with slightly different arguments. For example,

```=
stairs = beside-align("bottom", rectangle(50, 50, "solid", "gray"),
 beside-align("bottom", rectangle(50, 100, "solid", "gray"),
   beside-align("bottom", rectangle(50, 150, "solid", "gray"),
     rectangle(50, 200, "solid", "gray"))))
```

could be rewritten as:

```=
stair-width = 50
fun stair(height :: Number) -> Image:
  doc: "make an individual stair given its height"
  rectangle(stair-width, height, "solid", "gray")
end

stairs = beside-align("bottom", stair(50),
  beside-align("bottom", stair(100),
    beside-align("bottom", stair(150), stair(200))))
```

3. Make sure your helper functions and constants are not redundant in light of existing built-in functions. For example, there is no point in making this function:

```=
fun string-lower(s :: String) -> String:
  string-to-lower(s)
end
```
since you could always use `string-to-lower` instead.

## Clarity
1. Write docstrings for all functions, including helper and nested functions.
A good docstring gives a description of the function, including its input(s) and output. Ideally, by looking at the docstring you know what the function does and how to use it without looking at the function body itself.

```=
fun three-stripes(bot-col :: String, mid-col :: String,
    top-col :: String) -> Image:
  doc: ```makes a rectangular flag with three stripes. 
   the inputs describe the stripes' colors, bottom-to-top.```
  ...
end
```
<div class="alert alert-warning">
<h2 id="Bad-docstring-descriptions" data-id="Bad-docstring-descriptions"><a class="anchor hidden-xs" href="#Bad-docstring-descriptions" title="Bad-docstring-descriptions"><span class="octicon octicon-link"></span></a><span>Bad docstring descriptions</span></h2>
<ol>
<li><code>doc: "helper function for flag making"</code></li>
<li><code>doc: "output the right image for this problem"</code></li>
<li><code>doc: "uses above to stack images"</code><span> - how your function body actually works is irrelevant to the docstring.</span></li>
</ol>
</div>

2. Give constants and helper functions useful names.

```=
n1 = 3.1415
n2 = 500
n3 = 30
fun helper(x):
  x + 3
end
```
should be rewritten as (for example)

```=
pi = 3.1415
flag-width = 500
circle-radius = 30
fun add-3(x):
  doc: "adds three to its input x"
  x + 3
end
```

3. All functions require type annotations on both inputs and output.

4. Names of constants and functions should be lower case and dash separated. For configuration constants (for example the height of a character) it is acceptable to use all caps dash-separated names.

```=
# Good Pyret Style:
flag-width = 500
width-to-height-ratio = 3/5
CHARACTER-HEIGHT = 40

# Bad Pyret Style:
flag_width = 500
widthHeightRatio = 3/5
CharacterHeight = 40
```

5. Keep lines under 100 characters. You will at some point see a vertical dashed blue line in Pyret.

    If you see this line, your lines are too long and you need to add linebreaks (press `enter` at places in your code).

    The 100 character limit applies even when you have long strings and/or docstrings. Long docstrings can be written using backticks (`):

```=
fun f(x :: Number)
  doc: ```return 2; ignore inputs, always outputs 2 no matter
          what, this function is going to return 2```
  2
end
```

6. Indent your code properly. You can do this by pressing `ctrl-a` then `tab` on Windows and Linux, or `cmd-a` then `tab` on Mac.