Agile Javaв„ў: Crafting Code with Test-Driven Development
The new assertion verifies that the number of students enrolled in a brand-new session should be 0 (zero). The symbol 0 is a numeric literal that represents the integer zero. Specifically, it is an integer literal, known in Java as an int. Add the method getNumberOfStudents to CourseSession as follows: class CourseSession { ... int getNumberOfStudents() { return 0; } }
(The ellipses represent the instance variables, constructor code, and getter methods that you have already coded.) The return type of getNumberOfStudents is specified as int. The value returned from a method must match the return type, and in this method it doesgetNumberOfStudents returns an int. The int type allows variables to be created that store integer values from 2,147,483,648 to 2,147,483,647. Numbers in Java are not objects like String literals are. You cannot send messages to numbers, although numbers can be passed as parameters along with messages just like Strings can. Basic arithmetic support in Java is provided syntactically; for many other operations, support is provided by system libraries. You will learn about similar non-object types later in Agile Java. As a whole, these non-object types are known as primitive types. You have proved that a new CourseSession object is initialized properly, but you haven't shown that the class can enroll students properly. Create a second test method testEnrollStudents that enrolls two students. For each, create a new Student object, enroll the student, and ensure that the CourseSession object reports the correct number of students. public class CourseSessionTest extends junit.framework.TestCase { public void testCreate() { ... } public void testEnrollStudents() { CourseSession session = new CourseSession("ENGL", "101"); Student student1 = new Student("Cain DiVoe"); session.enroll(student1); assertEquals(1, session.getNumberOfStudents()); Student student2 = new Student("Coralee DeVaughn"); session.enroll(student2); assertEquals(2, session.getNumberOfStudents()); } } How do you know that you need a method named enroll, and that it should take a Student object as a parameter? Part of what you are doing in a test method is designing the public interface into a classhow developers will interact with the class. Your goal is to design the class such that the needs of developers who want use it are met in as simple a fashion as possible. The simplest way of getting the second assertion (that the number of students is two) to pass would be to return 2 from the getNumberOfStudents method. However, that would break the first assertion. So you must somehow track the number of students inside of CourseSession. To do this, you will again introduce a field. Any time you know you need information to be stored, you will likely use fields to represent object state. Change the CourseSession class to look like this: class CourseSession { ... private int numberOfStudents = 0; ... int getNumberOfStudents() { return numberOfStudents; } void enroll(Student student) { numberOfStudents = numberOfStudents + 1; } }
The field to track the student count is named numberOfStudents, it is private per good practice, and it is of the type int. It is also assigned an initial value of 0. When a CourseSession object is instantiated, field initializers such as this initialization of numberOfStudents are executed. Field initializers are executed prior to the invocation of code in the constructor. The method getNumberOfStudents now returns the field numberOfStudents, instead of the int literal 0. Each time the enroll method is called, you should increment the number of students by one. The single line of code in the enroll method accomplishes this: numberOfStudents = numberOfStudents + 1;
The + sign and many other mathematical operators are available for working with variables of the int type (as well as other numeric types to be discussed later). The expression on the right hand side of the = sign takes whatever value is currently stored in numberOfStudents and adds 1 to it. Since the numberOfStudents field appears to the left of the = sign, the resultant value of the right-hand side expression is assigned back into it. Bumping up a variable's value by one, as in this example, is a common operation known as incrementing the variable. There are other ways to increment a variable that will be discussed later. It may seem odd that numberOfStudents appears on both sides of the assignment operator. Remember that the Java VM always executes the right hand side of an assignment statement first. It calculates a result using the expression to the right, and assigns this result to the variable on the left. Note that the enroll method has a return type void, meaning that it returns nothing to the message sender. The class diagram in Figure 2.1 shows the existing structure of your system so far. Figure 2.1. CourseSession and Student Class Diagram
Conceptually, a course session should be able to hold several students. In realityin the codethe course session holds references to no student objects. It only holds a count of students. Later, when you modify the CourseSession class to actually store Student references, the UML diagram will be modified to show that there is a one-to-many relationship between CourseSession and Student. CourseSession depends on Student, since the enroll method can take a Student object as a parameter. In other words, you would not be able to compile the CourseSession class if the Student class did not exist. Figure 2.1 will be the last class diagram where I show every test class. Since you are doing test-driven development, future diagrams will imply the existence of a test class for each production class, unless otherwise noted. |