Test First Development

DUE: 11:59PM, Thursday 10 September 2015

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

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:

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

    • 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 Nick:2:10:10000.

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

  • Operations specific to Company

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

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

  • Operations specific to Project

    • missingQualifications() : Set(Qualification)
      Compare the 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 are met.

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

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

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

    Using Eclipse

    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 TestAll.  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
      cd a1-temp
      jar -xvf a1-bob.jar
      cd cs414/a1/bob
      javac -classpath pathToJUnit/junit(yourversion).jar:. ../../../  *.java
      etc.