| CompSci 308 Spring 2021 |
Advanced Software Design and Implementation |
As you program larger, more complex, projects it is vitally important that you have confidence that the most basic aspects of your code works correctly by automatically testing it. 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.
Testing on incremental, iterative, cycles that has become well established over the last twenty years because it helps make teams successful if they combine eXtreme Programming practices that re-enforce each other:
In pairs, complete the following activities today:
lab_testing into their own repository to allow pushing your group's changes
Settings -> Members to add your partner so both people in the group can access the same repositoryMaintainer role in the project and choose Add to Projectgit clone to copy the one forked repository to their individual machines so they can work on their own separate copiesFor shared WYSIWYG Markdown editing, you can use
At the end of lab, use Gitlab's Merge Request from your pair's forked repository's master branch back to the lab's original organization repository's master branch to submit your group's discussion summary and your test 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 what changes you made).
Make sure the Title of your Merge Request is of the form "lab_testing - everyone's NetIDs".
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 in the src folder and discuss what would be useful to test the code to validate that both the NanoBrowserModel and NanoBrowserView classes works as expected in the provided DISCUSSION.md file. 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
null, and empty, ""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.
For the following exercises, switch the person coding directly roughly every 15 minutes or every 1-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.
In the test folder, write test methods, annotated with @Test and with its own call to the appropriate JUnit assert statement or test for a thrown Exception, based on the values and scenarios from your discussion. Run the tests regularly to make sure they are passing! 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 and try to think of new test cases that would cover them.
In the test folder, write test methods, using TestFX to simulate common user "actions" and then checking important GUI properties with appropriate JUnit assert statement, based on the scenarios from your discussion. Run the tests regularly to make sure they are passing! 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 and try to think of new test cases that would cover them (including changing languages and styles).
Solve the following problem from scratch using TDD to try to establish a coding rhythm:
First, write a test in a separate well named method that shows the intention of the test, then write the most simple code to make that test pass (i.e., do not write a complex data structure until you need it).A parking garage provides a fixed number of parking spaces for vehicles and must maintain information about the vehicles that are currently in the parking garage so it can report the number of spaces available and the current value. A parking garage must provide publicly available functions to be called when a vehicle enters the garage and when a vehicle leaves the garage that throw exceptions if there is not enough available space in the garage, if a vehicle tries to enter that is already in the garage or if a car that is not in the garage tries to exit. Additionally, the garage must provide publicly available functions that report the total capacity of the garage, the number of available spaces in the garage, and the total money collected. The parking fee is a flat rate that is collected when a vehicle leaves the parking garage.
Currently, there are three distinct types of vehicles, cars, low-emission cars, cargo trucks. Every vehicle has a license number consisting of letters and/or numbers and the number of spaces it occupies. Cars have a passenger capacity (i.e., the number of passengers). Trucks have a gross vehicle weight it can transport. Cars take up one space, while trucks take up a number of spaces that is their gross weight divided by 10,000. Cars are charged a rate of $8, low-emission cars are charged half that rate, and trucks are charged $10 per 10,000 pounds of gross weight.
To show you are actually following the TDD process, you should have a lot of GIT commits that go together in pairs (where the first one represents a test that fails and the next one represents code that causes that test to pass). Obviously that is not how you would typically commit your code to the repository but this is just to establish that you are doing the work in the correct order.
In order to see the process more clearly when working as a pair, we strongly suggest that one person writes the test and the other person writes the code that passes the test (so one person writes the first test, the next person writes the code and the next test, then the first person writes the next code and the next test, etc.).
Note, you will not need to write a Main class or main() method or interact with the user for this exercise since the tests should fully exercise the code.
If you are having trouble thinking of how to come up with appropriate tests to follow this process, here is TDD challenge that shows a series of tests in the order you might write them for a different application (and in an older version of JUnit).