# Learn How to Auto-Grade

Auto-grading is a powerful tool that saves teachers time and provides students with feedback regarding the correctness of their solution before they submit it for a grade.&#x20;

All of this auto-grading magic can be accomplished with unit testing -- test whether parts (units) of a students code work properly by asserting that they meet certain conditions (equal to a predetermined value, produce a result in a given range, etc.).

{% content-ref url="/pages/-MSKLAz6\_KPMtlqXxLtO" %}
[Assertions and Unit Testing](/assertions-and-unit-testing)
{% endcontent-ref %}

{% content-ref url="/pages/-MSJzr251n\_u-7H\_MrIh" %}
[Python Examples](/python/check-variable-values)
{% endcontent-ref %}

{% content-ref url="/pages/-MSJzmKtkuA3TGI6hDxf" %}
[Java Examples](/java/check-variable-values)
{% endcontent-ref %}

{% content-ref url="/pages/J9btDXQ9RHHTyjkSR3f6" %}
[Ruby Examples](/ruby-examples/output-tests)
{% endcontent-ref %}

## Webinar

{% embed url="<https://www.youtube.com/watch?v=IVV_Wm9nRVo>" %}

{% embed url="<https://www.youtube.com/watch?v=782_j-BSG3g>" %}

{% embed url="<https://www.youtube.com/watch?v=M2PwwtDCBC8>" %}

{% embed url="<https://www.youtube.com/watch?v=m43PxYYgZ6g>" %}

## Quick Start

New to Unit Testing?  Let's do a brief review.&#x20;

TODO

### Python - unittest

&#x20;The basic building blocks of unit testing are *test cases* — single scenarios that must be set up and checked for correctness.

The simplest [`TestCase`](https://docs.python.org/3/library/unittest.html#unittest.TestCase) subclass will simply implement a test method (i.e. a method whose name starts with `test`) in order to perform specific testing code:

```python
def test_default_case(self):
    # Your test case logic here (replace the example assertion below)
    # You may also rename this to any function in the form of 'test_your_test_name(self):'
    self.assertTrue(True)
```

Note that in order to test something, we use one of the `assert*()` methods provided by the [`TestCase`](https://docs.python.org/3/library/unittest.html#unittest.TestCase) base class. If the test fails, an exception will be raised with an explanatory message, and [`unittest`](https://docs.python.org/3/library/unittest.html#module-unittest) will identify the test case as a *failure*. Any other exceptions will be treated as *errors*.

Tests can be numerous, and their set-up can be repetitive. Luckily, we can factor out set-up code by implementing a method called [`setUp()`](https://docs.python.org/3/library/unittest.html#unittest.TestCase.setUp), which the testing framework will automatically call for every single test we run:

```python
def setUp(self):
    # Setup code here (if required, replace the 'pass')
    pass
```

&#x20;Similarly, we can provide a [`tearDown()`](https://docs.python.org/3/library/unittest.html#unittest.TestCase.tearDown) method that tidies up after the test method has been run:

```python
def tearDown(self):
    # Teardown code here (if required, replace the 'pass')
    pass
```

&#x20;If [`setUp()`](https://docs.python.org/3/library/unittest.html#unittest.TestCase.setUp) succeeded, [`tearDown()`](https://docs.python.org/3/library/unittest.html#unittest.TestCase.tearDown) will be run whether the test method succeeded or not.

### Java - JUnit

TODO

```java
@Test
public void testDefaultCase() {
    // You may rename this method to better suit the purpose of your test case
    // Your test case logic here
}
```

```java
@Before
public void setUp() {
    // Setup code here (if required)
}
```

```java
@After
public void tearDown() {
    // Teardown code here (if required)
}
```

## Created and curated by Joe Mazzone

[Joe Mazzone](https://joemazzone.net/), former Computer and Software Engineering instructor at [William M. Davies, Jr. Career and Technical High School](https://www.daviestech.org/) in Lincoln, Rhode Island.

Joe is now a Senior Product Manager/Product Development Lead at John Wiley & Sons, Inc., working on [Coding Rooms](https://www.codingrooms.com/) and [zyBooks](https://www.zybooks.com/).

Like what Joe created?  ☕ Buy him a coffee: <https://www.buymeacoffee.com/JoeMazzone>


# Assertions and Unit Testing

## Python&#x20;

Full documentation - <https://docs.python.org/3/library/unittest.html>

| **Method**                                     | **Description**                                                                                   |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `assertEqual(first, second)`                   | Test that *first* and *second* are equal. If the values do not compare equal, the test will fail. |
| `assertNotEqual(first, second)`                | Test that first and second are not equal. If the values do compare equal, the test will fail.     |
| `assertAlmostEqual(first, second, delta=none)` | Test that first and second are approximately equal within a positive delta.                       |
| `assertListEqual(first, second)`               | Tests that two lists are equal.                                                                   |
| `assertTupleEqual(first, second)`              | Tests that two tuples are equal.                                                                  |
| `assertDictEqual(first, second)`               | Test that two dictionaries are equal.                                                             |
| `assertCountEqual(first, second)`              | Test that first and second have the same elements in the same number, regardless of their order.  |
| `assertGreater(first, second)`                 | Test first > second                                                                               |
| `assertGreaterEqual(first, second)`            | Test first >= second                                                                              |
| `assertLess(first, second)`                    | Test first < second                                                                               |
| `assertLessEqual(first, second)`               | Test first <= second                                                                              |
| `assertIs(first, second)`                      | Test that first and second are the same object.                                                   |
| `assertIn(member, container)`                  | Test that member is in container.                                                                 |
| `assertTrue(condition)`                        | Test that condition is true.                                                                      |
| `assertFalse(condition)`                       | Test that condition is false.                                                                     |

Why use `assertListEqual()` instead of just `assertEqual()`?  Well, they are designed to show the difference between the two values on failure.  So students will receive more accurate feedback if you use the proper assertion.

Feedback:

You can add feedback to assertion failures to alert students what they might have done wrong.  To do so, just simply add an additional argument as a string containing the message you want to display.

```python
assertEqual(student_output, real_output, "Looks like your code is not outputing the proper value.")
```

Useful Links:

* Skipping test and expected failures: <https://docs.python.org/3/library/unittest.html#skipping-tests-and-expected-failures>

## Java

Full documentation - <https://junit.org/junit4/javadoc/4.12/org/junit/Assert.html>

| **Method**                                            | **Description**                                             |
| ----------------------------------------------------- | ----------------------------------------------------------- |
| `assertEquals(expected, actual)`                      | Test that two values are equal.                             |
| `assertEquals(expected, actual, delta)` - for doubles | Test that two doubles are equal to within a positive delta. |
| `assertArrayEquals(expecteds, actuals)`               | Test that two arrays are equal.                             |
| `assertNotNull(object)`                               | Test that an object isn't null.                             |
| `assertNull(object)`                                  | Test that an object is null.                                |
| `assertNotSame(unexpected, actual)`                   | Test that two objects do not refer to the same object.      |
| `assertSame(unexpected, actual)`                      | Test that two objects refer to the same object.             |
| `assertTrue(condition)`                               | Test that a condition is true.                              |
| `assertFalse(condition)`                              | Test that a condition is false.                             |

Feedback:

You can add feedback to assertion failures to alert students what they might have done wrong.  To do so, just simply add a string containing the message you want to display as the first argument in the method call.

```python
assertEquals("Looks like your code is not outputing the proper value.", realOutput, studentOutput)
```

## Ruby

Ruby calls assertions "matchers"

Full documentation - <https://rspec.info/documentation/3.9/rspec-expectations/RSpec/Matchers.html>

<table><thead><tr><th width="230.91502237068875">Matcher</th><th>Description</th></tr></thead><tbody><tr><td><strong>Matcher</strong></td><td><strong>Description</strong></td></tr><tr><td><p><code>expect([]).to be_empty</code></p><p><code>expect([]).not_to be_empty</code></p></td><td><p># => [].empty?() | passes</p><p># => [].empty?() | fails</p></td></tr><tr><td><p><code>expect("a string").to be_an_instance_of(String)</code> </p><p><code>expect(3).to be_a_kind_of(Integer)</code> </p><p><code>expect(3).to be_a_kind_of(Numeric)</code> </p><p><code>expect(3).to be_an_instance_of(Integer)</code> <code>expect(3).not_to be_an_instance_of(Numeric)</code></p></td><td><p># => 3.kind_of?(Numeric) | passes </p><p># => 3.kind_of?(Numeric) | passes </p><p># => 3.instance_of?(Integer) | passes </p><p># => 3.instance_of?(Numeric) | fails</p></td></tr><tr><td><p><code>expect(5).to eq(5)</code></p><p><code>expect(5).not_to eq(3)</code></p></td><td></td></tr><tr><td><code>expect { print 'foo' }.to output('foo').to_stdout</code></td><td>Check function output to stdout</td></tr><tr><td><p><code>expect(5).to satisfy { |n| n > 3 }</code></p><p><code>expect(5).to satisfy("be greater than 3") { |n| n > 3 }</code></p></td><td></td></tr></tbody></table>


# Request / Submit Examples

## Want To See an Example Not Listed?

Something you want to be able to do, not sure how, and an example that would help is not listed here?  Submit an auto-grading example request!  I will try my best to create the example, post it here, and notify you.&#x20;

{% embed url="<https://forms.gle/f8Bm6TTFfoqEWMPi7>" %}

## Have an Example You Want to Share?

Have you created an example not listed here?  I would love to showcase it!  Submit what you have and I will add it here, credit you, and send you a thank you email. 😁

{% embed url="<https://forms.gle/PMMiUggdFjrV4gNYA>" %}


# Check Variable Values

## Simple variable value

To check a variable value you need to import the student's code and use dot notation to get the value.

Example, maybe you ask students to assign a variable named `num1` the value of `5`.

**Student Code:**

{% code title="example.py" %}

```python
num1 = 5
```

{% endcode %}

**Grading Tests:**

```python
import unittest

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        import example
        self.assertTrue(example.num1 == 5)

if __name__ == '__main__':
    unittest.main()
```

## Number of items in a list

You can do anything you need to with a student's variable value.  For example, we can see if a student created a list with at least 3 items using the `len()` function.&#x20;

**Student Code:**

{% code title="example.py" %}

```python
my_list = ["first thing", "second thing", "third thing"]
```

{% endcode %}

**Grading Tests:**

```python
import unittest

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        import example
        self.assertTrue( len(example.my_list) >= 3 )

if __name__ == '__main__':
    unittest.main()
```


# Output Tests

This is an example of how you can test the output stream of student code.&#x20;

This test makes sure the student's code prints `"Hello World"`.  It assumes the student's file name is `example.py`.  Replace the import with whatever you student's file name is.&#x20;

*Note:  This code converts the output to all lowercase and removes spaces to compare against the correct value.*

#### **Grading Tests:**

```python
import unittest
import sys, io

stdout = sys.stdout

class CodingRoomsUnitTests(unittest.TestCase):

    def setUp(self):
        global stdout
        stdout = sys.stdout
        sys.stdout = io.StringIO()

    def tearDown(self):
        global stdout
        sys.stdout = stdout
        
    def test_default_case(self):
        import example
        
        output = sys.stdout.getvalue().strip("\n")

        answer = "Hello World".casefold().replace(" ", "")
        student = output.casefold().replace(" ", "")
        
        self.assertEqual(answer, student)

if __name__ == '__main__':
    unittest.main()
```

#### Sample Solution:

{% code title="example.py" %}

```python
print("Hello World")
```

{% endcode %}


# Input / Output Tests

This is an example of how you can mock input values and test the output stream of student code.&#x20;

The student must use the `input()` function to prompt the user for their first name, the again for their last name.  Then, print `Hello, firstname lastname!` including the person's first and last name.&#x20;

**Sample Run:**

```
What is your first name? Jane
What is your last name? Doe
Hello, Jane Doe!
```

It assumes the student's file name is `example.py`.  Replace the import with whatever you student's file name is.&#x20;

*Note:  This code converts the output to all lowercase and removes spaces to compare against the correct value.*

#### **Grading Tests:**

```python
import unittest
import sys, io
import importlib

stdout = sys.stdout
stdin = sys.stdin
student_code = ""

class CodingRoomsUnitTests(unittest.TestCase):

    def setUp(self):
        global stdout
        global stdin
        stdout = sys.stdout
        stdin = sys.stdin

    def tearDown(self):
        global stdout
        global stdin
        sys.stdin = stdin
        sys.stdout = stdout

    def test_case_1(self):
        global student_code
        sys.stdout = io.StringIO()
        sys.stdin = io.StringIO("Jane\nDoe")

        student_code = importlib.import_module('example')

        output = sys.stdout.getvalue().strip("\n")
        
        self.assertTrue(output.casefold().replace(" ", "").endswith("Hello, Jane Doe!".casefold().replace(" ", "")))

    def test_case_2(self):
        global student_code
        sys.stdout = io.StringIO()
        sys.stdin = io.StringIO("Joe\nMazzone")

        importlib.reload(student_code)

        output = sys.stdout.getvalue().strip("\n")
        
        self.assertTrue(output.casefold().replace(" ", "").endswith("Hello, Joe Mazzone!".casefold().replace(" ", "")))

if __name__ == '__main__':
    unittest.main()
```

The `io.StringIO()` for `stdin` replaces the programs input stream.  Each input must be separated by a newline character - `\n`.

You will also notice that the assertion doesn't compare the output directly with what is expected.  Instead it sees if the output stream `.endswith()` the expected output. This is because the `input()` function's prompt is included in the output stream, so we only want to check the last thing printed.  If you want to include the prompts to ensure students properly included them, you can use `assertEqual()` and and compare the entire output stream

#### Sample Solution:

{% code title="example.py" %}

```python
fname = input("What is your first name?")
lname = input("What is your last name?")

print("Hello, " + fname + " " + lname + "!")
```

{% endcode %}


# Print Function Tests

This is an example of how you can test the output stream of a student defined function.&#x20;

This test makes sure the student's function named `print_hello()` prints `"Hello World"`.  It assumes the student's file name is `example.py`.  Replace the import with whatever you student's file name is.&#x20;

*Note:  This code converts the output to all lowercase and removes spaces to compare against the correct value.*

#### **Grading Tests:**

```python
import unittest
import sys, io

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        stdout = sys.stdout
        sys.stdout = io.StringIO()
        import example
        example.print_hello()
        output = sys.stdout.getvalue().strip("\n")
        sys.stdout = stdout
        answer = "Hello World".casefold().replace(" ", "")
        student = output.casefold().replace(" ", "")
        self.assertEqual(answer, student)

if __name__ == '__main__':
    unittest.main()
```

#### Sample Solution:

{% code title="example.py" %}

```python
def print_hello():
    print("Hello World")
```

{% endcode %}


# Return Function Tests

Each example assumes the students file name is `example#.py` replacing # with the actual example number.  You can call the functions by importing the student file name of your choice.&#x20;

## Example 1 - Add Five

Students write an function named `add_five()` that takes an integer as a parameter and returns 5 plus the parameter value.&#x20;

#### **Grading Tests:**

```java
import unittest

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        import example1
        self.assertEqual(10, example1.add_five(5))
        self.assertEqual(5, example1.add_five(0))
        self.assertEqual(11, example1.add_five(6))
```

#### Sample Solution:

{% code title="example1.py" %}

```python
def add_five(number):
    number += 5
    return number
```

{% endcode %}

## Example 2 - Average

Students write a function that takes 5 values as parameters and returns the average value of the 5 values.  The function must be named `average()` and it must have 5 parameters.&#x20;

Example: Calling `average(1, 5, 7, 4, 10)` would return `5.4`.

Note: Almost Equal assertion is used with a delta value as tolerance when comparing values.

#### **Grading Tests:**

```python
import unittest
import sys, io

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        import example2
        self.assertAlmostEqual(5.4, example2.average(1, 5, 7, 4, 10), delta=0.001)
        self.assertAlmostEqual(9.6, example2.average(5, 9, 24, 6, 4), delta=0.001)
       
if __name__ == '__main__':
    unittest.main()
```

#### Sample Solution:

{% code title="example2.py" %}

```python
def average(a, b, c, d, e):
    sum = a + b + c + d + e
    return sum / 5
```

{% endcode %}

## Example 3 - Repeats

Students write a function that takes a parameter. If the String parameter has a double letter (i.e. contains the same letter twice in a row) then it should return true. Otherwise, it should return false.

This function must be named `has_repeat()` and have a parameter. This function must return a `boolean`.

#### **Grading Tests:**

```python
import unittest
import sys, io

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        import example3
        self.assertTrue(example3.has_repeat("mississippi"))
        self.assertFalse(example3.has_repeat("capsized"))
        self.assertTrue(example3.has_repeat("mazzone"))
        self.assertFalse(example3.has_repeat("this"))
       
if __name__ == '__main__':
    unittest.main()
```

#### Sample Solution:

{% code title="example3.py" %}

```python
def has_repeat(word):
    count = 0
    for letter in word:
        if letter == word[count-1]:
            return True
        count += 1
    return False
```

{% endcode %}


# Random Number Tests

Testing code that includes random numbers can be hard.  Luckily, the random module comes with the `seed()` function.&#x20;

The `seed()` function allows you to initialize the random number generator with a specific value , which forces it to produce the same values each time.&#x20;

## Example 1 - Student Function

In this example, students are supposed to create a function named `make_random_numbers()` which returns a list of 10 random numbers between 20 and 99 inclusive.&#x20;

#### **Grading Tests:**

```python
import unittest
import random

class CodingRoomsUnitTests(unittest.TestCase):

    def test_case1(self):
        import example
        random.seed(10)
        self.assertListEqual([93, 24, 74, 81, 93, 21, 46, 79, 82, 55], example.make_random_numbers())

    def test_case2(self):
        import example
        random.seed(55)
        self.assertListEqual([31, 45, 39, 58, 30, 43, 58, 31, 65, 80], example.make_random_numbers() )
    
    def test_case3(self):
        import example
        random.seed(2)
        self.assertListEqual([27, 31, 30, 66, 41, 59, 52, 97, 47, 97], example.make_random_numbers())

if __name__ == '__main__':
    unittest.main()
```

Notice that `random.seed()` is called, setting the randomly generated numbers to predetermined values, before you check if the functions return value equals the expected value.&#x20;

#### Sample Solution:

{% code title="example.py" %}

```python
import random

def make_random_numbers():
    numbers_list = []
    for num in range(10):
        numbers_list.append(random.randint(20,99))
    return numbers_list
```

{% endcode %}

## Example 2 - Random Seed for random.randint()

Even better, we can randomly generate the seed and make the test random each time!

This example expects the student to use the `randint()` function to generate and print a random numbers between 0 and 500.

**Grading Tests:**

```python
import unittest
import sys, io
import random

stdout = sys.stdout

class CodingRoomsUnitTests(unittest.TestCase):

    def setUp(self):
        global stdout
        stdout = sys.stdout
        sys.stdout = io.StringIO()

    def tearDown(self):
        global stdout
        sys.stdout = stdout
        
    def test_default_case(self):
        s = random.randint(1, 55)
        
        random.seed(s)
        import main
        output = sys.stdout.getvalue()

        random.seed(s)
        num = random.randint(0, 500)

        answer = str(num)
        student = output
        
        self.assertEqual(answer, student)

if __name__ == '__main__':
    unittest.main()
```

**Sample Solution:**

{% code title="example.py" %}

```python
import random

random_num = random.randint(0,500)

print(random_num)
```

{% endcode %}

## Example 3 - Random Seed for random.choice()

Here is another where the student needed to print a random item from a list they created named `student_list`.

**Grading Tests:**

```python
import unittest
import sys, io
import random

stdout = sys.stdout

class CodingRoomsUnitTests(unittest.TestCase):

    def setUp(self):
        global stdout
        stdout = sys.stdout
        sys.stdout = io.StringIO()

    def tearDown(self):
        global stdout
        sys.stdout = stdout
        
    def test_default_case(self):
        s = random.randint(1, 55)
        
        random.seed(s)
        import example
        
        output = sys.stdout.getvalue().strip("\n")
        student = output

        random.seed(s)
        answer = random.choice(example.student_list)
        
        self.assertEqual(answer, student)

if __name__ == '__main__':
    unittest.main()
```

**Sample Solution:**

{% code title="example.py" %}

```python
import random

student_list = ["first thing", "second thing", "third thing", "fourth thing"]

random_thing = random.choice(student_list)

print(random_thing)
```

{% endcode %}


# Parse Student Code

Check if student used \_\_\_\_\_ in their code.

Often you just want to make sure students successfully used a particular function/command/structure.  The simplest way I have found to do this is just parse the student's code file and make sure what you are looking for is there.

## Example 1 - Used \_\_\_\_ function \_\_\_\_ times

For example, maybe you want to make sure the student used the input function 4 times.  We can parse the student's code file and count how many times `"input("` is present in their code.

This test assumes the student's file name is `example.py`.

**Grading Test:**

```python
import unittest

count = 0

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        global count
        f = open("example.py", "r")
        lines = f.readlines()
        f.close()
        
        for line in lines:
            line = line.strip().split()
            for words in line:
                if words.find("input(") != -1:
                    count += 1
                    
        self.assertTrue(count == 4)
        

if __name__ == '__main__':
    unittest.main()
```

Notice that the test asserts that the count is equal to 4. Of course you can change this condition to anything you want. For example, if you want to make sure they have at least 1 `input()` you could use `count >= 1`.

**Sample Solution:**

{% code title="example.py" %}

```python
name = input("What is your name?")
age = input("What is your age?")
hair = input("What color is your hair?")
place = input("Where do you live?")
```

{% endcode %}

## Example 2 - Used \_\_\_\_ thing \_\_\_\_ times

Sometimes if you are checking for a specific character/symbol it is better to use the `.count()` method so you do not miss an instance of the character/symbol.

This example checks that the student used the `+` addition at least 2 times. &#x20;

**Grading Test:**

```python
import unittest

count = 0

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        global count
        f = open("example.py", "r")
        lines = f.readlines()
        f.close()
        
        for line in lines:
            line = line.strip().split()
            for words in line:
                if words.find("+") != -1:
                    count += words.count("+")

        self.assertTrue(count >= 2)

if __name__ == '__main__':
    unittest.main()
```

## Example 3 - Used \_\_\_\_ function with these exact arguments

Since spaces can be used between arguments, to check if a function is called with exact arguments, you want to check each line of the student's code and remove all spaces.  Then find the function call you are looking for.&#x20;

This example checks that there is at least 1 call of `randint(501,1000)` in the student's code.

**Grading Test:**

```python
import unittest

count = 0

class CodingRoomsUnitTests(unittest.TestCase):

    def test_default_case(self):
        global count
        f = open("example.py", "r")
        lines = f.readlines()
        f.close()
        
        for line in lines:
            line = line.strip().replace(" ", "")
            if line.find("randint(501,1000)") != -1:
                count += 1
                
        self.assertTrue(count >= 1)

if __name__ == '__main__':
    unittest.main()
```


# Check Variable Values

Checking variable values can be a bit tricky in Java.  For example, it can be hard to check the following variable values.&#x20;

```java
class Example 
{
    public static void main(String[] args) 
    {
        String firstName = "Bob";
        String lastName = "Jones";
        System.out.println(firstName);
        System.out.println(lastName);
    }
}
```

This is because `firstName` and `lastName` are local to the `main()` method and created when it is executed and destroyed when it is done.&#x20;

We can prevent this by declaring these variables as static outside the `main()` method.

```java
class Example
{
    static String firstName;
    static String lastName;
 
    public static void main(String[] args)
    {
        firstName = "Bob";
        lastName = "Jones";
        System.out.println(firstName);
        System.out.println(lastName);
    }
}
```

We typically do not teach students to declare variables this way (most curriculums do not) so you may need to tweak your curriculum to auto-grade early assignments that teacher variable assignment and console output.

The grading test involves calling the main method (where you expect the variables to be assigned values and checking that each variable equals the expected value.

```java
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import static org.junit.Assert.*;

public class CodingRoomsUnitTests {

    @Test
    public void testDefaultCase() {
        Example.main(null);
        assertEquals(Example.firstName, "Bob");
        assertEquals(Example.lastName, "Jones");
    }
}
```


# Output Tests

This is an example of how you can test the output stream of student code.&#x20;

This test makes sure the student's code prints `"Hello World"`.  It assumes the student's file name is `Example.java`.  Replace the `Example.main(null)` call with whatever you student's file name is.&#x20;

*Note:  This code converts the output to all lowercase and removes spaces to compare against the correct value.*

#### **Grading Tests:**

```java
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.*;


public class CodingRoomsUnitTests {
    
    private final PrintStream standardOut = System.out;
    private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();

    @Before
    public void setUp() {
        System.setOut(new PrintStream(outputStreamCaptor));
    }

    @After
    public void tearDown() {
        System.setOut(standardOut);
    }

    @Test
    public void testDefaultCase() {
        Example.main(null);
        assertEquals("Hello World".toLowerCase().trim().replace(" ", ""), outputStreamCaptor.toString().toLowerCase().trim().replace(" ", ""));
    }    
}
```

#### Sample Solution:

{% code title="Example.java" %}

```java
public class Example
{
    public static void main(String[] args)
    {
        System.out.println("Hello World");
    }
}
```

{% endcode %}


# Input / Output Tests

This is an example of how you can mock input values and test the output stream of student code.&#x20;

The student must use the `Scanner`'s  `nextLine()` function to prompt the user for their first name, the again for their last name.  Then, print `Hello, firstname lastname!` including the person's first and last name.&#x20;

Sample Run:

```
What is your first name? 
Jane
What is your last name? 
Doe
Hello, Jane Doe!
```

It assumes the student's file name is `Example.java`.  This can be easily replaced with whatever your student's file name is.&#x20;

*Note:  This code converts the output to all lowercase and removes spaces to compare against the correct value.*

#### **Grading Tests:**

```python
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.*;

public class CodingRoomsUnitTests {
    
    private final PrintStream standardOut = System.out;
    private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();

    @Before
    public void setUp() {
        System.setOut(new PrintStream(outputStreamCaptor));
    }

    @After
    public void tearDown() {
        System.setOut(standardOut);
    }

    @Test
    public void testCase1() {
        String input = "Joe\nMazzone";
        InputStream in = new ByteArrayInputStream(input.getBytes());
        System.setIn(in);
        Example.main(null);
        assertTrue(outputStreamCaptor.toString().toLowerCase().trim().replace(" ", "").endsWith("Hello Joe Mazzone!".toLowerCase().trim().replace(" ", "")));
    }

    @Test
    public void testCase2() {
        String input = "Clark\nKent";
        InputStream in = new ByteArrayInputStream(input.getBytes());
        System.setIn(in);
        Example.main(null);
        assertTrue(outputStreamCaptor.toString().toLowerCase().trim().replace(" ", "").endsWith("Hello Clark Kent!".toLowerCase().trim().replace(" ", "")));
    }

    @Test
    public void testCase3() {
        String input = "Bruce\nWayne";
        InputStream in = new ByteArrayInputStream(input.getBytes());
        System.setIn(in);
        Example.main(null);
        assertTrue(outputStreamCaptor.toString().toLowerCase().trim().replace(" ", "").endsWith("Hello Bruce Wayne!".toLowerCase().trim().replace(" ", "")));
    }
}
```

The `input` String replaces the programs input stream.  Each input must be separated by a newline character - `\n`.

You will also notice that the assertion doesn't compare the output directly with what is expected.  Instead it sees if the output stream `.endsWith()` the expected output. This is because the we print other values as prompts for the Scanner input, so we only want to check the last thing printed.  If you want to include the prompts to ensure students properly included them, you can use `assertEqual()` and and compare the entire output stream.

#### Sample Solution:

{% code title="Example.java" %}

```python
import java.util.Scanner;

public class Example
{
    public static void main(String[] args)
    {
        Scanner scan = new Scanner(System.in);
        
        System.out.println("What is your first name?");
        String fName = scan.nextLine();
        
        System.out.println("What is your last name?");
        String lName = scan.nextLine();
        
        System.out.println("Hello, " + fName + " " + lName + "!");
    }
}
```

{% endcode %}


# Return Method Tests

Each example assumes the students file name is `Example#.java` replacing # with the actual example number.  You can call the methods based on the student filename of your choice.&#x20;

## Example 1 - Add Five

Students write an `int` method named `addFive(int number)` that takes an integer as a parameter and returns an `int` equal to 5 plus the parameter value.&#x20;

#### **Grading Tests:**

```java
import org.junit.Test;
import static org.junit.Assert.*;

public class CodingRoomsUnitTests {
    @Test
    public void testDefaultCase() {
        // You may rename this method to better suit the purpose of your test case
        // Your test case logic here
        assertEquals(10, Example1.addFive(5));
        assertEquals(5, Example1.addFive(0));
        assertEquals(11, Example1.addFive(6));
    }
}
```

#### Sample Solution:

{% code title="Example1.java" %}

```java
public class Example1 
{
    public static int addFive(int number)
    {
        number += 5;
        return number;
    }
}
```

{% endcode %}

## Example 2 - Average

Students write a method that takes 5 `int` values as parameters and returns the average value of the 5 ints as a `double`.  The method must be named `average()` and it must have 5 `int` parameters. The method must return a `double`.

Example: Calling `average(1, 5, 7, 4, 10)` would return `5.4`.

Note: Assertions with doubles must have delta value (tolerance when comparing values).

#### **Grading Tests:**

```java
import org.junit.Test;
import static org.junit.Assert.*;

public class CodingRoomsUnitTests {
    @Test
    public void testDefaultCase() {
        // You may rename this method to better suit the purpose of your test case
        // Your test case logic here
        assertEquals(5.4, Example2.average(1, 5, 7, 4, 10), 0.001);
        assertEquals(9.6, Example2.average(5, 9, 24, 6, 4), 0.001);
    }
}
```

#### Sample Solution:

{% code title="Example2.java" %}

```java
public class Example2
{
    public static double average(int a, int b, int c, int d, int e)
    {
        //Calculate sum of 5 numbers
        int s = a + b + c + d + e;
        //cast s to double and divide by 5
        return (double) s / 5;
    }
}
```

{% endcode %}

## Example 3 - Repeats

Students write a method that takes a String parameter. If the String has a double letter (i.e. contains the same letter twice in a row) then it should return true. Otherwise, it should return false.

This method must be named `hasRepeat(String str)` and have a `String` parameter. This method must return a `boolean`.

#### **Grading Tests:**

```java
import org.junit.Test;
import static org.junit.Assert.*;

public class CodingRoomsUnitTests {
    @Test
    public void testDefaultCase() {
        // You may rename this method to better suit the purpose of your test case
        // Your test case logic here
        assertTrue(Example3.hasRepeat("mississippi"));
        assertFalse(Example3.hasRepeat("capsized"));
        assertTrue(Example3.hasRepeat("mazzone"));
        assertFalse(Example3.hasRepeat("this"));
    }
}
```

#### Sample Solution:

{% code title="Example3.java" %}

```java
public class Example3
{
    public static boolean hasRepeat(String str)
    {
        for(int i = 0; i < str.length()-1; i++)
        {
            if(str.substring(i, i+1).equals(str.substring(i+1, i+2)))
            {
                return true;
            }
        }
        return false;
    }
}
```

{% endcode %}


# Class - .toString() and Void Method Tests

This page shows how you can do some auto-grading of classes that only have void methods (methods that do not return a value) and a `.toString()` method.&#x20;

This is completed by testing the output stream produced by the methods as they are called.&#x20;

In this example, the comparison is completed with all character converted to lowercase and all spaces removed.  If you want a pure character for character match, remove the `.toLowerCase().trim().replace(" ", "")` from the assertion.

## Example 1 - Employee Class

Students had to create an Employee class that has the following instance variables:&#x20;

* `String` employee’s name
* `int` their 4 digit id number
* `double` hourly salary

Then, create a constructor method that sets each instance variable to the parameter values given to the constructor call.

Also, they must create a `toString()` method that prints the Employee's name, 4 digit id, and salary in the following format:

```
John Doe -- 4545 -- $15.67 per hour
```

Lastly, they must create a method called `getRaise(double amount)` that increases the employee's salary by the specified amount and prints `“Nice you got a $” + amount + “ raise!”`

For example, if we print the Employee object, call `getRaise(1.0)`, and print the Employee object again, the following would be created.

```
John Doe -- 4545 -- $15.67 per hour
Nice you got a $1.0 raise!
John Doe -- 4545 -- $16.67 per hour
```

To auto-grade this, use the following -- you can run as many tests as your want!

First, there are two tests that ensure the `.toString()` method is working properly.  They create an object with the Employee class, print the object, and ensure the print stream matches the expected output (remember, this example compares the two strings as all lowercase and with spaces removed).

Second, the `.getRaise()` method is tested with two different tests.  The object is instantiated, `.getRaise()` is called, and then the object is printed to confirm that it effected the `salary` field.  Note that that the print stream is reset between `.getRaise()` and printing the object so that each print statement can be tested asserted separately but within the same test.&#x20;

#### Grading Tests:

```java
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.*;


public class CodingRoomsUnitTests {
    
    private final PrintStream standardOut = System.out;
    private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();

    @Before
    public void setUp() {
        System.setOut(new PrintStream(outputStreamCaptor));
    }

    @After
    public void tearDown() {
        System.setOut(standardOut);
    }

    @Test
    public void testToString1() {
        Employee e = new Employee("John Doe", 4545, 15.67);
        System.out.println(e);
        String answer = "John Doe -- 4545 -- $15.67 per hour".toLowerCase().trim().replace(" ", "");
        String output = outputStreamCaptor.toString().toLowerCase().trim().replace(" ", "");
        assertEquals(answer, output);
    }

    public void testToString2() {
        Employee e = new Employee("Bob Bobbington", 5555, 10.5);
        System.out.println(e);
        String answer = "Bob Bobbington -- 5555 -- $10.5 per hour".toLowerCase().trim().replace(" ", "");
        String output = outputStreamCaptor.toString().toLowerCase().trim().replace(" ", "");
        assertEquals(answer, output);
    }

    public void testGetRaise1() {
        Employee e = new Employee("Bob Bobbington", 5555, 10.5);
        e.getRaise(1);
        assertEquals(outputStreamCaptor.toString().toLowerCase().trim().replace(" ", ""), "Nice you got a $1.0 raise!".toLowerCase().trim().replace(" ", ""));
        System.setOut(standardOut);
        System.setOut(new PrintStream(outputStreamCaptor));
        System.out.println(e);
        String answer = "Bob Bobbington -- 5555 -- $11.5 per hour".toLowerCase().trim().replace(" ", "");
        String output = outputStreamCaptor.toString().toLowerCase().trim().replace(" ", "");
        assertEquals(answer, output);
    }

    public void testGetRaise2() {
        Employee e = new Employee("Bob Bobbington", 5555, 10.5);
        e.getRaise(0.4);
        assertEquals(outputStreamCaptor.toString().toLowerCase().trim().replace(" ", ""), "Nice you got a $0.4 raise!".toLowerCase().trim().replace(" ", "");
        System.setOut(standardOut);
        System.setOut(new PrintStream(outputStreamCaptor));
        System.out.println(e);
        String answer = "Bob Bobbington -- 5555 -- $10.9 per hour".toLowerCase().trim().replace(" ", "");
        String output = outputStreamCaptor.toString().toLowerCase().trim().replace(" ", "");
        assertEquals(answer, output);
    }   
}
```

#### **Sample Students Solution:**

```java
public class Employee 
{ 
    private String name; 
    private int id; 
    private double salary;
    
    public Employee(String n, int i, double s) 
    {
        name = n;
        id = i;
        salary = s;
    }
    public String toString() 
    {
        return name + " -- " + id + " -- $" + salary + " per hour";
    } 

    public void getRaise(double amount)
    {
        salary += amount;
        System.out.println("Nice you got a $" + amount + " raise!");
    }
}
```


# Random Numbers Tests

TODO


# Array and ArrayList Tests

TODO


# Parse Student Code

Often you just want to make sure students successfully used a particular function/command/structure.  The simplest way I have found to do this is just parse the student's code file and make sure what you are looking for is there.

For example, maybe you want to make sure the student used `println()` at least 2 times.  We can parse the student's code file and count how many times `"System.out.println("` is present in their code.

This test assumes the student's file name is `Example.java`.

```java
import org.junit.Test;
import static org.junit.Assert.*;
import java.nio.file.*;

public class CodingRoomsUnitTests {

    @Test
    public void testDefaultCase() throws Exception {
        int count = 0;
        String student_code = new String(Files.readAllBytes(Paths.get("Example.java")));
        String[] words = student_code.split(" ");

        for (int i = 0; i < words.length; i++) {
            if (words[i].indexOf("System.out.println(") >= 0) {
                count++;
            }
        }
        assertTrue(count >= 2);
    }
}
```


# Output Tests

This is an example of how you can test the output stream of student code.&#x20;

This test makes sure the student's code prints `"Hello World"`.  It assumes the student's file name is `example.rb`.  Replace the `require` with whatever your student's file name is.&#x20;

*Note:  This code converts the output to all lowercase and removes spaces to compare against the correct value.*

#### **Grading Tests:**

```ruby
require 'rspec'
require 'stringio'

RSpec.describe "CodingRoomsUnitTests" do

    describe 'Checking file output' do
        it "output should equal 'Hello World'" do
            io = StringIO.new()
            $stdout = io
            load '/usercode/example.rb'
            $stdout = STDOUT
            expect(io.string).to eq("Hello World\n")
        end
    end
    
end
```

#### Sample Solution:

{% code title="example.rb" %}

```ruby
puts 'Hello World'
```

{% endcode %}


# Input / Output Tests

This is an example of how you can mock input values and test the output stream of student code.&#x20;

The student must use the `puts` function to prompt the user for their first name, then use `gets.chomp` to collect the first name without a newline attached, and again for their last name.  Then, print `Hello, firstname lastname!` including the person's first and last name.&#x20;

**Sample Run:**

```
What is your first name?
Jane
What is your last name?
Doe
Hello, Jane Doe!
```

It assumes the student's file name is `example.rb`.  Replace the `require` with whatever your student's file name is.&#x20;

*Note: This code converts the output to all lowercase and removes spaces to compare against the correct value.*

#### **Grading Tests:**

```ruby
require 'rspec'
require 'stringio'

student_code = File.read("/usercode/example.rb") 
new_student_code = student_code.gsub(" gets", " $stdin.gets") 
File.open("/usercode/example.rb", "w") do |f|
  f.write(new_student_code)
end

RSpec.describe "CodingRoomsUnitTests" do

    describe 'Giving code Jane and Doe as inputs' do
        it "output should equal 'Hello, Jane Doe!'" do
            input = StringIO.new()
            output = StringIO.new()
            input.puts "Jane"
            input.puts "Doe"
            input.rewind
            $stdin = input
            $stdout = output
            load '/usercode/example.rb'
            expect(output.string).to include("Hello, Jane Doe!")
            $stdin = STDIN
            $stdout = STDOUT
        end
    end

    describe 'Giving code Joe and Mazzone as inputs' do
        it "output should equal 'Hello, Joe Mazzone!'" do
            input = StringIO.new()
            output = StringIO.new()
            input.puts "Joe"
            input.puts "Mazzone"
            input.rewind
            $stdin = input
            $stdout = output
            load '/usercode/example.rb'
            expect(output.string).to include("Hello, Joe Mazzone!")
            $stdin = STDIN
            $stdout = STDOUT
        end
    end

end
```

RSpec, the unit testing framework we are using, seems to have a hard time replacing the standard input stream.  That is why you see this code at the beginning of our test file.

```ruby
student_code = File.read("/usercode/example.rb") 
new_student_code = student_code.gsub(" gets", " $stdin.gets") 
File.open("/usercode/example.rb", "w") do |f|
  f.write(new_student_code)
end
```

To allow RSpec to load a new standard input stream, we need to replace all instances of `gets` and use `$stdin.gets`. Instead of teaching students to not use `gets` and always use `$stdin.gets`, we can simply add the above code to replace all instances of `gets` with `$stdin.gets`.

***Note:** On Coding Rooms, the testing instance copies the student code so the above doesn't actually modify the student submission, it just changes it for the test.  Other platforms or your local may behave differently.*

#### Sample Solution:

{% code title="example.rb" %}

```ruby
puts 'What is your first name?'
firstname = gets.chomp

puts 'What is your last name?'
lastname = gets.chomp

puts 'Hello, ' + firstname + " " + lastname + "!"
```

{% endcode %}


# Print Function Tests

This is an example of how you can test the output stream of a student defined function.&#x20;

Ruby makes this super easy with the `output` matcher.&#x20;

`expect { print 'foo' }.to output('foo').to_stdout`

This test makes sure the student's function named `prints_name()` that takes a name as a parameter and prints `"Hello, {name provided}!"` to standard output.  It assumes the student's file name is `example.rb`.  Replace the `require` with whatever your student's file name is.&#x20;

#### **Grading Tests:**

```ruby
require 'rspec'
require 'stringio'
require '/usercode/example'

RSpec.describe "CodingRoomsUnitTests" do

    describe "Run prints_name() with 'Jane'" do
        it "expects output to be 'Hello, Jane!'" do
            expect{prints_name("Jane")}.to output("Hello, Jane!\n").to_stdout
        end
    end

    describe "Run prints_name() with 'Fred'" do
        it "expects output to be 'Hello, Fred!'" do
            expect{prints_name("Fred")}.to output("Hello, Fred!\n").to_stdout
        end
    end

end

```

#### Sample Solution:

{% code title="example.rb" %}

```ruby
def prints_name(name)
    puts 'Hello, ' + name + "!"
end

prints_name("Jane")
```

{% endcode %}


# Return Function Tests

Students writes a function named `add_five()` that takes an integer as a parameter and returns 5 plus the parameter value.&#x20;

#### **Grading Tests:**

```ruby
require 'rspec'
require 'stringio'
require '/usercode/exampleb'

RSpec.describe "CodingRoomsUnitTests" do

    describe "Run add_five() with parameter 5" do
        it "expect the function to return 10" do
            expect(add_five(5)).to eq(10)
        end
    end

    describe "Run add_five() with parameter 0" do
        it "expect the function to return 5" do
            expect(add_five(0)).to eq(5)
        end
    end

    describe "Run add_five() with parameter 6" do
        it "expect the function to return 11" do
            expect(add_five(6)).to eq(11)
        end
    end

end
```

#### Sample Solution:

{% code title="example.rb" %}

```ruby
def add_five(number)
    number += 5
    return number
end

puts add_five(5)rub
```

{% endcode %}


# Parse Student Code

Often you just want to make sure students successfully used a particular function/command/structure.  The simplest way I have found to do this is just parse the student's code file and make sure what you are looking for is there.

The following example looks for the `for` keyword and checks that the student has used a for loop at least 1 time.&#x20;

***Note:** You may want to add more logic to this code if you heavily rely on it.  I have it check if the for is on a line with a comment or in a puts statement but technically there are other ways for students to pass the code by putting a for somewhere.*

**Grading Test:**

```ruby
require 'rspec'
require 'stringio'

RSpec.describe "CodingRoomsUnitTests" do

    describe "Code requires at least 1 FOR loop" do
        it "checking that coding has >= 1 FOR loop" do
            count = 0
            File.open("/usercode/example.rb").each do |line|
                if (line.include?('for') and !(line.include?('#') or line.include?('puts')))
                    count += 1
                end
            end
            expect(count).to be >= 1
        end
    end

end
```


