CompSci 308
Spring 2023
Advanced Software Design and Implementation

Lab Exercise : Testing

As you program larger, more complex, projects it is vitally important, and some would say morally imperative, that you have confidence that the most basic aspects of your code works correctly based on automatically testing it (rather than manual, occasional, tests). JUnit is the most common automated test framework for Java that focuses on testing individual methods. It has inspired similar frameworks in almost every other modern language and is built in to all major IDEs, including IntelliJ. It has even been important in changing developers habits, by practicing of test-driven development (TDD), so they produce tests along with their code features (and, better yet, before writing their code) instead of waiting until the code is complete.

Submitting your Work

At the end of lab, use Gitlab's Merge Request from your forked repository's master branch back to the original organization repository's master branch to submit your group's discussion summary and your test code.

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

Resources

Lab Workflow

In pairs, complete the following activities today:

  1. On Gitlab, one person should fork the updated version of the project lab_browser into their own repository to allow pushing your group's changes
    • On the resulting project web page, go to Project Information → Members (in the upper left corner) to add your partner so both people in the group can access the same repository
    • Search for your partner's name and give them a Maintainer role in the project and choose Add to Project
  2. In Terminal, both students should use git clone to copy the one forked repository to their individual machines so they can work on their own separate copies
  3. In IntelliJ, both students should Open the cloned folder to create a new project on their personal machine
  4. Together, discuss testing strategies and think of as many tests as you can
  5. In IntelliJ, implement your proposed tests for the Model using JUnit only
  6. In IntelliJ, implement your proposed user interaction tests for the View using TestFX with JUnit

Discussion

Code's functionality is verified manually by running it and automatically by writing tests. But how do you assess the quality of the tests? Does test suite quality and coverage matter? YES! While all code likely contains bugs, it is vitally important to minimize them because software is literally a matter of life and death.

Examine the existing browser code and discuss what would be useful to test the code to validate that both the NanoBrowserModel and NanoBrowserView classes works as expected. Consider different strategies for thinking of the kinds of values that would represent "happy" and "sad" possible code paths (here are many, many, many specific examples rather than general strategies in case you are having trouble thinking of possible negative tests) and write down as many tests as you can (specific values for the Model and specific user actions in the View).

It is impossible to guarantee code is completely free of bugs, but try to come up with a set of tests that check every line of code written works as intended. For example, check

Test data can come from data files, explicit data Strings, or explicit data Lists, but each test should be documented as to their purpose, i.e., how does these input values relate to the written code, both with a descriptive name and with traditional comments that explain what code it is testing and why. 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). Finally, make sure you know the expected output values for each test before you run the code.

Testing

Write the tests your team discussed for both the Model and View classes. As you create tests, try to develop a working rhythm and run the tests regularly to make sure they all pass.

For the following exercises, switch the person coding directly roughly every 2-3 tests. The other person, the "navigator", should be actively helping the coding process by making suggestions or looking up documentation. Each person should get plenty of time to both come up with testing values/scenarios as well as code the tests.

Testing the Model

Based on the values and scenarios from your discussion, add tests to the Model Test class, src/test/java/browser/model/NanoBrowserModelTest.java, by writing new test methods:

After you have written all the tests you can think of, run them all again with test coverage to see how well you did checking every line (of course, that will not guarantee the code is bug free, just that you did a reasonable job thinking of a variety of test cases). If the Line Coverage is less than 90%, look over the lines that were missed (marked by red in the Editor window gutter within IntelliJ) and try to think of new test cases that would cover them.

Testing the View

Based on the values and scenarios from your discussion, add tests to the View Test class, src/test/java/browser/view/NanoBrowserViewTest.java, by writing new test methods:

After you have written all the tests you can think of, run them all again with test coverage to see how well you did checking every line. If the Line Coverage is less than 60%, look over the lines that were missed (marked by red in the Editor window gutter within IntelliJ) and try to think of new test cases that would cover them (including changing languages and styles).