CompSci 308
Spring 2025
Advanced Software Design and Implementation

Lab Coding Exercise: Unit Testing

As you program larger, more complex, projects it is vitally important that you have confidence the most basic aspects of your code works correctly by automatically testing it — meaning the tests can be run as often as needed to test the entire program, not just the most recent code. JUnit, the most common automated framework for Java, focuses on testing individual methods and has inspired similar frameworks in every other modern language.

Resources

Specifications

In your teams, write new tests for (and, as needed, debug) the following programs using your forked version of the lab_unitest project. Make sure each person gets to write a variety of tests and that every few tests, you add, commit, and push your changes.

Write as many tests as you can think of to verify the code and, in the process, find any bugs or other issues with the code using these steps:

  1. Add a new JUnit test to verify whether or not the code works as intended
  2. Run all the tests to verify they all continue to pass (both the old and new tests show green)
  3. If you find a bug: (i.e., a test fails by showing red)
    1. Comment out the buggy code
    2. Write a comment telling the cause of the error
    3. Write the correct code that fixes the error
  4. Again, run all the tests to verify they all continue to pass

Each test should be:

Use the ZOMBIES acronym to help you remember to consider these questions when coming up with useful scenarios to test the program:

  1. What would be the most simple data you could make to test the program does something reasonable?
  2. What "special cases" does the program check for (or not)?
  3. What "categories" does program behavior naturally fall into? What data shows the boundaries of those categories?
  4. What "bad" data values you can think of and what checks would you add to the code to make it more robust from failure or a nonsensical answer?

Resist the urge to simply create a lot of "random" tests (i.e., the shotgun approach) and focus on making each test as useful as possible (i.e., the sniper approach).

You can also check which lines of code are not executed by your tests.

Buggy Programs

Container

This is a very buggy example in a few lines of code, even though the given tests all pass!

There are at least 5 errors in the code. Update the JUnit code by writing only new tests to verify the existing bugs. How you fix the bugs is entirely up to you, but fix one at a time to emphasize thinking about different strategies for what to test (e.g., do not simply change the implementation to an ArrayList and fix all the compilation errors since that will likely fix most of the bugs without you having to think about tests for each).

Bowling

This program simulates scoring a game of bowling, which consists of 10 connected frames to provide bonuses for knocking down all 10 pins within the frame. Thus, the maximum possible score you can achieve is 300, by rolling twelve strikes in a row, instead of 120, the simple value of 10 pins scored directly for 12 rolls.

There is at least 1 error in the code. Update the JUnit code by writing only new tests to verify the existing bug(s).

Here is an interactive scorer to help you develop and verify your test cases.

 

Submitting your Work

At the end of lab, use Gitlab's Merge Request from your forked repository's main branch back to the original organization repository's main branch to submit your team's tested code.

You only need to create one Merge Request, no matter how many commits you make, and you do not worry about potential conflicts since your request will not be approved (it is just an easy way for us to see changes you made).

Make sure the Title of your Merge Request is of the form "lab_unittest - everyone's NetIDs".