Lab 6 - Automatic Tests & Refactoring
Introduction
Demo Application - Test Automation and JUnit
The code base for the demo application is here: lab6-testing-demoapp.zip.
Project has three Java model classes (none of the classes has the main
method because we are not dealing with the independently executable application). Project consists of only the following model classes:
SaleItem
- Can be used for different products. Each product has a name and unit price.Bill
- One bill record. Consists of one more more rows. Can calculate the total sum of the rows.BillRow
- One row in the bill. Has a link to the corresponding product (SaleItem) and sold quantity number. Can have also discount percentage for the concrete sale and product (by default discount percentage is 0%). Can calculate row total price.
Application code is located in the \src
folder. In addition, the project includes also the automatic unit tests created using the JUnit framework. The code of the tests is located in the \test
folder. Tests can be executed with an ANT target test
or running with eclipse built-in tools (Ctrl+F11 või Alt+Shift+X,T).
For training: Test classes have many empty test methods that should check different model properties and functionality. Try to develop these tests.
Note! One of the classes has several mistakes in error handling. Can you find it with tests?
Demo Application - Refactoring.
The code base for the demo application is here: lab6-refactoring-demoapp.zip. This project does not have the ANT build script. You need to import and run it with Eclipse.
Application is reading data about doctors and patients from the CSV files located in the project root folder. After reading the files, application creates corresponding objects and prints them to the console. However, the application code is far from perfection and has many problems, especially related to the code duplication. You need to refactor the code and make it better. Hint: You can use inheritance/generalization and split/combine methods.
Homework
Task 1. Covering POS with Automatic Tests.
Add JUnit framework support to your POS project. You need to add the corresponding jar file junit-4.10.jar as a library to your project, create one more source folder test
for your test classes and add ANT script target to run the tests (see first demo application as an example).
Most of the applications (and SalesSystemis is not an exception) have many classes. Some of them is difficult or not reasonable to cover with the unit tests (depend on many external actions, etc). Ease of the unit test development is a sign of a good architecture and design.
In your current SalesSystem version such difficulties are: external database, Hibernate and their strong relationship with other application parts. Also it is quite difficult to test fat client GUI. Nevertheless, it is relatively easy to cover model classes and JTable helping classes like StockTableModel
. Here is the list of the classes and tests that should be implemented:
SaleTest/PurchaseTest/...
(name depends on your solution of the lab 4):testAddSoldItem()
testGetSumWithNoItems()
testGetSumWithOneItem()
testGetSumWithMultipleItems()
StockItemTest
testClone()
testGetColumn()
SoldItemTest
testGetSum()
testGetSumWithZeroQuantity()
StockTableModelTest
testValidateNameUniqueness()
testHasEnoughInStock()
testGetItemByIdWhenItemExists()
testGetItemByIdWhenThrowsException()
- You need to develop the tests above. You also should add your own tests where possible. Do not implement trivial tests like checking if the class constructor creates a new object or checking if the getter method returns the same value that the setter method set!
- Find at least two more model classes that can be covered with nontrivial unit tests. Implement unit tests for found classes.
Task 2. Refactoring.
For this task we will use the following code: lab6-refactoring-POS.zip
PurchaseInfoTableModel
has a List<SoldItem>
(inherited from class SalesSystemTableModel
) and Sale
has a Set<SoldItem>
. You should get rid of this code duplication. The most reasonable way to do it would be to use the Sale
object in the PurchaseInfoTableModel
to get the rows. To add this modification in the architecture you need to remove List<T> rows
from SalesSystemTableModel
class and change the method public List<T> getTableRows
to abstract, that would be then implemented separately in each inheriting class.
In the given project all stock tab, client tab and history tab data refresh action on data change. You need to rewrite this logic and refresh the tab data (load latest state from the database) on the tab select action.
The use of the object model during the Sale should be approximately as following:
- User chooses the client and makes the purchase
Client client = …
Sale sale = new Sale(client);
- User chooses the product and adds it to the cart:
StockItem stockItem = …
// create the SoldItem object if needed and add it to the sale or use already existing one and change the quantitysale.addItem(stockItem);
- User completes the purchase:
sale.setSellingTime(new Date());
Replace the methodsubmitCurrentPurchase(List<SoldItem> goods, Client currentClient)
with the new method:salesDomainController.registerSale(sale);
For sure you also need the StockItem quantity
Recommended work order:
- Temporarily forget all the GUI and modify the object model according to the instructions above.
- Fix the GUI. Start from the
SaleSystemTableModel
, where you will loose therows
. Next, modify theXxxTableModel
classes -PurchaseInfoTableModel
will use theSale
object,StockTableModel
should keep it's own rows. - Add
refresh()
method to the stock, client and history tabs to load the latest state from the database. The table rows should be read from the database using the domain controller and passed to the models. Remember to trigger the refresh on every tab activation. - Code cleanup. Obviously, there would be many unused methods left after the refactoring like in class
SalesDomainControllerImpl
. You need to remove all unused code.
Submission of the Results
- Your repository should now have two folders. The first folder with the task 1 solution should have the name task1. The second folder with the task 2 solution should have the name task2.
- Create a new tag with name homework_6 where you commit the final solutions (both folders), comment this tag with "Homework 6". As a result your general solution on the GitHub should have the link:
- https://github.com/[account name]/[repo name]/tree/homework_6