Test First Development

DUE: 11:59PM, Saturday 10 September 2016 (Note the change from 8 Sept)

25 points


Objectives

  • Review programming in Java given a design specification
  • Become familiar with environment (java, javac, eclipse)
  • Become familiar with JUnit
  • Practice test-first development

Getting started

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; Test Infected; and the JUnit Cookbook. Information on JUnit can be obtained from www.junit.org. A useful FAQ can be found here. 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.


Tasks

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.

Company Class Diagram

The classes are Company, Worker, Project, and Qualification. The enumeration types are ProjectStatus and ProjectSize, each with their shown values.

Classes are shown with their names (e.g., Company), attributes (e.g., name of type String), and operations (e.g., createProject, which takes a project name, a set of Qualification instances, and project size, and returns a Project instance.

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.

In the above diagram, associations are shown between two classes. For example, the association Requires between Project and Qualification indicates that a project require a certain set of qualifications (at least one qualification). The same qualification may be required in zero or more projects. Sometimes two classes may be related by multiple associations (e.g., Worker and Company) and both of these associations need to be implemented/enforced by your code.

Associations must be implemented using appropriate data structures (e.g., a set should be implemented using a HashSet, not an ArrayList).

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. Do not include print statements anywhere in your code.

The specification for the operations are listed below:

  • Operations specific to Company:

    1. Company(name: String) Constructor
      Creates a company instance, and sets the name.

    2. getName(): String
      Returns the name of the company.

    3. getAvailableWorkers(): Set(Worker)
      Returns a Set of available workers. Note that the order is unimportant, and your tests must reflect that as well.

    4. getAssignedWorkers(): Set(Worker)
      Returns a Set of assigned workers. Note that the order is unimportant, and your tests must reflect that as well.

    5. getUnassignedWorkers(): Set(Worker)
      Returns a Set of available workers who are not assigned to any project. Note that the order is unimportant, and your tests must reflect that as well.

    6. equals(o: Object) : boolean
      This operation is needed by JUnit. Note that the argument to this operation must be of type Object, i.e. not equals (c : Company), etc. You will override the equals(o: Object) method inherited by the class. Two Company instances are equal if an only if their names match. Note that it is good practice to override the hashCode method when equals is overridden.

    7. toString() : String
      Returns a String that includes the company name, colon, number of available workers, colon, and number of projects carried out. For example, a company called ABC that has 20 available workers and 10 projects will result in the string ABC:20:10.

    8. addToAvailableWorkerPool(w : Worker) : void
      A worker "w" who is currently not in the pool of available workers gets added to the pool of available workers.

    9. assign(w : Worker, p: Project) : void
      Only workers from the pool of available workers can be assigned as long as they are not already assiged to the same project. The project must not be in the ACTIVE or FINISHED state. The worker should not get overloaded by adding to this project. The worker can be added only if the worker is helpful to the project. If the conditions are satisfied, (1) the assigned worker is added to the pool of assiged workers of the company unless they were already present in that pool, and (2) the worker is also added to the project. This results in at least one previously unmet required qualification of the project being met.

      Note that the same worker can be in both the available pool and assigned pool of wokers at the same time. However, the worker cannot be in the assigned pool if they are not in the available pool. Think of the available pool as the pool of employed workers.

    10. unassign(w : Worker, p : Project) : void
      The worker must have been assiged to the project to be unassigned. If this was the only project for the worker, then delete this worker from the pool of assigned workers of the company. If the qualification requirements of an ACTIVE project are no longer met, that project is marked SUSPENDED. A PLANNED OR SUSPENDED project remains in that state.

    11. unassignAll(w : Worker) : void
      Remove the worker from all the projects that were assigned to the worker. Also remove the worker from the pool of assigned workers of the company. Change the state of the affected projects as needed.

    12. 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).

    13. finish(p : Project) : void
      An ACTIVE project is marked FINISHED. The project no longer has any assigned workers, so if a worker was only involved in this project, remove them from the pool of assigned workers of the company. A SUSPENDED or PLANNED project remains as it was.

    14. createProject(n : String, qs : Set(Qualification), size : ProjectSize, status: ProjectStatus) : Project
      A new project is created and is entered in the set of projects carried out by the company. For each qualification in qs, add the qualification in the qualification requirements set of the project. The project is marked as PLANNED. The name and size of the project are also set.

  • Operations specific to Worker

    1. Worker(name : String, qs : Set(Qualification)): Constructor
      Creates a new worker with the given name, and the set of qualifications. Default salary is 0.

    2. getName(): String
      Gets the name field.

    3. getSalary(): Double
      Gets the salary field.

    4. setSalary(salary : Double) void
      Sets the salary field.

    5. getQualifications(): Set(Qualification)
      Gets the qualifications of the worker as a Set (order is not important).

    6. addQualification(q : Qualification): void
      Add the qualification q to the set of qualifications of the worker. Note that sets don't contain duplicates.

    7. equals(o: Object) : boolean
      This operation will be used by JUnit. Note that the argument to this operation must be of type Object, i.e. not equals (w : Worker), etc. You will override the equals(o : Object) method inherited by the class. Two Worker instances are equal if and only if their names match.

    8. toString() : String
      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 Nick:2:10:10000.

    9. willOverload(p : Project) : boolean
      Returns true if a worker will be overloaded if the worker gets assigned to the project "p", false otherwise. A constraint for the entire system is that no worker should ever be overloaded. To determine overloading, consider all the ACTIVE projects the worker is involved in. If adding the new project to the existing projects of the worker makes (3*number_of_big_projects + 2*number_of_medium projects + number_of_small_projects) greater than 12, then the worker will be overloaded.

  • Operations specific to Qualification

    1. Qualification(description : String): Constructor
      Creates a new instance of qualification using the description.

    2. equals(o: Object) : boolean
      This operation will be used by JUnit. Note that the argument to this operation must be of type Object, i.e. not equals(q : Qualification), etc. You will override the equals(o : Object) method inherited by the class. Two Qualification instances are equal if and only if their descriptions match.

    3. toString() : String
      Returns the description.

  • Operations specific to Project

    1. Project(name: String, size : ProjectSize, status: ProjectStatus) : constructor
      Creates an instance of a project with the name, size and status.

    2. getName(): String
      Returns the name of the project.

    3. getSize(): ProjectSize
      Returns the size of the project.

    4. getStatus(): ProjectStatus
      Returns the status of the project.

    5. setStatus(s : ProjectStatus) : void
      Sets the status of the project.

    6. equals(o : Object) : boolean
      This operation will be used by JUnit. Note that the argument to this operation must be of type Object, i.e. not equals (p : Project), etc. You will override the equals(o : Object) method inherited by the class. Two Project instances are equal if and only if their names match.

    7. toString() : String
      Returns a String that includes the name, colon, number of assigned workers, colon, status. For example, a project named "CS5Anniv" using 10 assigned workers and status PLANNED will result in CS5Anniv:10:PLANNED. In the string, status is in upper case (as shown in the UML class diagram).

    8. missingQualifications() : Set(Qualification)
      Compare the qualifications required by the project and those that are met by the workers who are assigned to the project. Return the qualifications that are not met. An empty set (not null set) is returned when all the qualification requirements are met. The order of qualifications is not important.

    9. 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.


    Submission

    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 files (note that the Java files are source files, not class files):

    • CompanyTest.java: Contains tests for the class, Company
    • Company.java
    • WorkerTest.java: Contains tests for the class, Worker
    • Worker.java
    • ProjectTest.java: Contains tests for the class, Project
    • Project.java
    • QualificationTest.java: Contains tests for the class, Qualification
    • Qualification.java
    • ProjectStatus.java
    • ProjectSize.java
    • TestAll.java: Defines the test suite for all the tests of this homework.
    • 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. We will test your implementation using our test cases. We will evaluate the quality of your test cases according to their ability to detect known faults in our own implementation. We may also read your submitted code.

    Points will be deducted if you don't meet the submission requirements stated above. 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 the GTA.

    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.


    Grading criteria

    • 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.