Test First Development
11:59PM, Thursday 10 September 2015
- Review programming in Java given a design specification
- Become familiar with environment (java, javac, eclipse)
- Become familiar with JUnit
- Practice test-first development
Read the entire assignment before starting to code. That way you will get a
full picture of what is needed.
Read the notes on Testing, TDD, and JUnit; Chapter 4 in the Fowler text;
Infected; and the
Information on JUnit can be obtained from
JUnit is already integrated with Eclipse.
Test execution is tied to the Eclipse
debugger, so you can view what went wrong. Test driver skeletons are
generated; you just need to fill in the test cases.
The figure below shows the design of a project management system. The
UML class diagram shows the necessary classes and enumeration
types that you must implement.
The classes are Company, Worker, Project, and
Qualification. The enumeration types are ProjectStatus
and ProjectSize, each with their shown values.
Clases are shown with their names (e.g., Company), attributes
(e.g., name of type String), and operations (e.g.,
createWorker, which takes a worker nickname and set of
Qualification instances, and returns a Worker.
Assume that worker nicknames are unique. So are project names, qualification
descriptions, and company names. You don't need to implement checks for
uniqueness. Test data will contain only unique names.
Associations are shown between two classes. For example, the association
IsQualified between Worker and Qualification
indicates that some worker may have a certain qualification (or more).
The association roles and multiplicities at the end are to be implemented
such that every worker has one or many qualifications
(denoted by 1..*, and every qualification can be traced back to
zero or more workers (denoted by *).
Your task is to use test first development to implement the above design, including all the classes, all the associations, and all the enumerated types. The specification for the operations are listed below:
Operations specific to Company
- Print statements cannot be included anywhere in your code.
- Do not include a main method in any of the classes in the above class diagram.
- Operations needed in every class (not in enums):
- Constructors and getter-setter operations:
Note that UML class diagrams typically do not show constructors and
getter-setter operations. However, you may need to implement some of them
in each class depending on the other methods that you will implement.
Getter-setter operations can be implemented both for attributes
(e.g., getName() in Company) and association roles
(e.g., getEmployer() for Worker and getWorkers()
for Company. Most likely, set operations will be few or
- equals(Object o) : Boolean
This operation will be used by JUnit. Note that the argument to this operation
must be of type Object, i.e. not equals Project p), etc.
You will override the equals(Object o) method inherited by the class.
Figure out what properties need to be checked for equality for each class.
- toString() : String
- For Company, toString returns a String that
includes the company name, colon, number of employees, colon, and number
of projects carried out. For example, a company called ABC that has 20
employees and 10 projects will result in the string ABC:20:10.
- For Worker, toString returns a String that
includes the nickname, colon, #projects, colon, #qualifications, colon, salary.
For example, a worker named "Nick", working on 2 projects, and having 10
qualifications and a salary of 10000 will result in the string
- For Project, toString returns a String that
includes the name, colon, number of employees, colon, status. For example, a project named
"CS5Anniv" employing 10 people and status planned will result in
CS5Anniv:10:planned. In the string, status is in lower case (as shown in the UML class diagram.
- For Qualification, toString returns the
Operations specific to Worker
- hire(w : Worker) : void
Only non-employees can be hired. The hired worker is included in the employed
workers. The worker is also added to all small projects (not medium or big
projects) that were planned or suspended because some qualifications required
in the project could not be previously satisfied, but can be partially or
completely satisfied by this worker. If the worker completely satisfies the
remaining requirements, that project is marked active (i.e., the project is
started). Otherwise, the project remains planned or suspended.
- fire(w : Worker) : void
Only employees can be fired. Remove
the worker from the workers role of the company. If the worker was a member
of any project, then delete the worker from that project. If the qualification
requirements of that project are no longer met, that project is marked
suspended. The worker is also removed from the list of workers for each of the
qualifications this worker had.
- start(p : Project) : void
A planned or suspended project may be
started as long as the project's qualification requirements are all satisfied.
This project is now in active status. Otherwise, the project remains planned or
suspended (i.e., as it was before the method was called).
- finish(p : Project) : void
An active project is marked finished. The project no longer has any workers
as members. A suspended or planned project remains as it was.
- createWorker(nn : String, qs : Set(Qualification)) : Worker
Creates a new worker with the given nn as nickname, and the set of
qualifications. This worker is added to the list of workers. For each
qualification in the set qs, this method makes sure that the worker
is added to the list of workers matching that qualification.
- createProject(n : String, ws : Set(Worker),
qs : Set(Qualification), s : ProjectSize) : Project
A new project is created and is entered in the list of projects carried out
by the company. For each worker in ws, add the worker to the members
list of the project. For each qualification in qs, add the
qualification in the qualification requirements list of the project. The
project is marked as planned. The name and size of the project are also set.
Only employees can be members of a project.
Operations specific to Project
- isOverloaded() : Boolean
Returns true when a worker is overloaded,
false otherwise. A constraint for the entire system is that no worker should
be overloaded. To determine overloading, consider all the active projects
the worker is involved in. If 1*number_of_big_projects + 2*number_of_medium projects is greater than 4, then the worker is overloaded.
- missingQualifications() : Set(Qualification)
qualifications required by the project and those that are met by the workers
who are members of the project. Return the qualifications that are not met.
An empty set (not null set) is returned when all the qualification requirements
- isHelpful(w : Worker) : Boolean
If at least one of the
missing qualification requirements of a project is satisfied by the worker,
then return true, else return false.
Implement your JUnit test cases such that the test cases for each class in the class diagram appear in a separate file. For example, the test cases for Company must be written in CompanyTest.java and so on. Thus, you will have four test files CompanyTest.java, WorkerTest.java, ProjectTest.java, and QualificationTest.java. You should also have a file called TestAll.java that defines the test suite for all the tests in this assignment. If during the development of test cases you feel that some specifications are missing, feel free to make up your own and note them in an overview document.
All the classes that you write must be in a package called cs414.a1.yourEID.
Submit a jar or a zip file, A1-youreID.jar or A1-youreID.zip, which
includes the following:
- CompanyTest.java: Contains tests for the class, Company
- WorkerTest.java: Contains tests for the class, Worker
- ProjectTest.java: Contains tests for the class, Project
- QualificationTest.java: Contains tests for the class, Qualification
- TestAll.java: Defines the test suite for all the tests of this
- overview.txt: A short overview paper, providing
information that is not readily available from reading
the code, incomplete specifications, things that gave you
trouble, etc. This paper should be plain ASCII text.
The folder (or directory) hierarchy must be cs414/a1/yourEID. The Java source
files must be present in the yourEID folder of the hierarchy. When you create
the jar/zip file, build it from the top of the directory hierarchy. The
submitted file must correctly unpack the .java files into a subdirectory
cs414/a1/yourEID. The grader will cd to the appropriate directory, run
javac *.java, and launch JUnit on cs414.a1.yourEID.TestAll. In addition,
the grader will read all of your code, and may run it by hand against sample
It's extremely important to submit your work using the specified form.
If your work does not meet that form, you will receive no credit for the
assignment. This may seem harsh. However, the grader will have a relatively
large number of assignments to grade. Guessing how to unpack and compile
individual assignments can take a lot of time, and is an unfair burden on
Make sure you submit all of your test code in addition to the code
for all your classes in the form of Java files, not bytecode.
Submit a single jar or zip file, submitted using Assignment Submission in Canvas.
- Functionality of the implementation classes (implement methods correctly): 11 points
- Functionality of test classes: 11 points
- Programming style: 3 points
Up to 5 points may be deducted for not following the packaging structure or
names used for the classes and the methods of each class.
Click here for steps on using Eclipse
to work on the assignment and create the final jar file for submission. Note
that the screenshots will differ based on the version of Eclipse used and
certain other configuration and environmental factors. Also, note that the steps
were used in a previous semester that involved different classes
(World, Coordinate, WorldTest, and CoordinateTest,
and for a different package starting with cs414dl.
In case you are using the command line to edit and compile your programs,
here's an example. Bob codes up the Java files and the test classes.
He tries them out, and is satisfied that they work. Bob verifies that the
.java files build cleanly by doing an rm *.class (Be careful not to delete
your source files by accident!), and javac *.java. Bob verifies
that all of the tests are running and pass at 100% by using JUnit on
Bob feels ready to submit.
First, Bob jars everything up. He types
- cd topdir
jar -cvf a1-bob.jar cs414/a1/bob/*.java
topdir is the parent directory of cs414/a1/bob.
In case you want to try out the jar file just like a grader would do, you
can use the following example on the command line (departmental unix machines
or your own machine, assuming you have the Java commands installed).
Bob makes a new directory under topdir and copies the jar file there. There he tries an
unpack, compile, and run:
- mkdir a1-temp
cp a1-bob.jar a1-temp
jar -xvf a1-bob.jar
javac -classpath pathToJUnit/junit(yourversion).jar:. ../../../ *.java