Before beginning any work, do a Team...Pull in your repository.
- Thanks to Doug Shook, who developed this lab assignment.
However, any errors here are the fault of the current instructor.
Your task is to generate two classes: Student and Course using a test-driven development approach. This means that your goal is to get the unit tests to pass, and you develop your code incrementally to get more of the tests to pass.
First, take a look at the StudentAndCourseTest.java file. In that file you will see unit tests. Unfortunately, none of the tests will currently pass. You use these tests as you develop your classes to verify whether they are working as intended. You are also encouraged to write some additional tests of your own. Be sure to test often!
You do not need to check the box that generates the main method. We won't be running your Student class directly, but instead testing its functionality via the unit test.
It is important as you work on this lab that you do not change the existing tests in StudentAndCourseTest. You may add tests, but the existing tests must be preserved.
We will test your code after you commit and push to make sure it passes the tests as given, and credit may be revoked if you do not pass the given tests!
Add these properties as instance variables to your class, create a constructor, create some getters and setters, and test!
How do you know what to name your instance variables? How do you name the getters and setters? Good questions, and this relates to encapsulation.
Your instance variables can, should, and must be declared private. In this way, their names are not exposed outside the Student class, which protects them from unintended access. More on this as you read further.
On the other hand, the getters and setters may be referenced by the unit test. The names and type signatures of your method must conform to their use in the unit test. For example, the testStudentInit method in StudentAndCourseTest contains the constructor call:Student s = new Student("Doug", "Shook", 111111)From this line we can reason that the constructor takes in a String, another String, and an int. We can also reason that the first parameter of the constructor is the student's first name, and the second parameter is the student's last name.
You can similarly read the test code in StudentAndCourseTest to see how the getters and setters are named.
We now pause for a teaching moment. Why the fuss about encapsulation?
- Suppose you wanted to count the number of times a student's ID is accessed. If the instance variable is public, then access to the variable's value can occur in any other class, beyond the view of the Student class. By making the instance variable private, and requiring a getter to access the value, the Student class can count the number of accesses to the value.
- Suppose you wanted for some reason to change the representation of a student's ID from an integer to a string, or suppose you really want to change the name of the instance variable. If you made the variable public, then other code may subsequently be written that requires the name and type of the instance variable to stay the same.
By making the instance variable private, you encapsulate it within the Student class and you have control therefore over that instance variable's future.
- Suppose you decide that a student's ID should not be a settable property of a Student, by any code outside the Student class. If you make the instance variable public, code outside of the Student class can read or write the instance variable. Only by making the variable private can you arrange for the value to be manipulable within the Student class, but not outside of that class.
Encapsulation allows us to retain control over some aspects of a class's specification, while releasing only those portions that are necessary by design.
This point is emphasized below when we ask you to consider computing the worry factor of a Student.
Recall the has-a concept presented in the course videos. As you read through the methods below and consider their implementation, you may develop a feeling that your class should have something it does not yet have. Feel empowered to introduce other instance variables as necessary. Remember that they too deserve nice names, they should be initialized in your constructor(s), but they do not need (nor should they have) getters or setters. They are used to manage data within your class.
But first, what about those ??? marks in the type for grade? You must figure out the type for grade by looking into the unit test and seeing what kind of values are supplied for that parameter. The grade could be an int or a double, so only the unit test can show you what is needed.
A helpful hint: if you pause your mouse over a variable, eclipse will tell you the type of that variable. I know, right? Too good to be true.
GPA can be computed by the following formula:
Take the number of credits for a course and multiply it by the grade for that course. This is called the quality score. GPA is computed as the sum of all of the quality scores for each course the student has taken, divided by the total number of credits.
You must also round the GPA so that it only contains three digits after the decimal.
Run the unit test again, and at this point both testStudentInit and testSubmitGrade should pass.
|Fewer than 30||"FirstYear"|
|30 or more but fewer than 60||"Sophomore"|
|60 or more but fewer than 90||"Junior"|
|90 or more||"Senior"|
What should you do now? Oh you already know: run the unit test again.
At this point, which tests should be passing?
Wait, how can there be two parents for createLegacy when the method has just one parameter: otherParent?Here is what this method must do:
You must remember that every non-static method in an object has access to this: the object (often called the receiver) upon which the method was called. So, if the code a.createLegacy(b) is executed, then within createLegacy, object a is bound to this, and object b is bound to otherParent.
Thus, createLegacy has access to two Student objects, this and otherParent, and you are asked to consider each of those as a parent of the new Student object that will be returned by this method.
Hint: it may be useful to create an additional constructor!
The reason is that the constructor you already have sets the GPA and such to 0, but for this method, you need to construct a student with an existing GPA.
This new constructor should be private, not public. Do you see why?
Can you arrange for the previous, public constructor to call this new private one via this(…)? This idea is covered in the videos but here are some extra resources:
To reason about this, you need to think about what the unit test is doing, and you must provide getters or setters so that it can work. But beyond that, think about how this class will be used.
- Should the student ID have a setter? That is, do we want to provision for the student ID of a Student object to change? What does the initial story of a Student object say about that?
- How about the name? Washington University allows students to change their names.
- Should the number of credits be settable directly outside the class? Or should access be more carefully controlled?
The TAs will discuss this with you when you demo.
You will get credit for this lab without implementing the above idea, but your instructors consider it fair game to place such a question on an exam.
The Course class should contain the following properties:
As before drive your software development by the unit test.
Avoid creating extra functionality that is not demanded by the unit test or specifically required in this document. This approach saves you time and keeps the resulting code simple.
How will you check that the student has not already enrolled? You'll have to keep track of the students as they enroll. Fortunately, when a Course object is constructed, we know the maximum number of seats that the course offers, so we know the maximum number of enrolled students.
From what we have studied, what is the appropriate data type to keep track of enrolled Students in a Course?
When you are done with this lab, you must be cleared by the TA to receive credit.
- Do a Team…Pull to update your repository. You must do this or the commit/push below may fail.
- Commit and push all your work to your repository.Make certain this has worked by logging into bitbucket. There you will see the commit(s) in your news feed if it was successful. You can also check the Source page to locate and ensure your code was received.
It is your responsibility to make certain the code has been pushed. Some of your work receives credit through testing of your pushed code. You will receive no credit for such work if you failed to push. We generally reserve the right to revoke credit for any of your work that has not been pushed on-time.
- Fill in the form below with the relevant information
- Have a TA check your work
- The TA should check your work and then fill in the TA's name
- Click OK while the TA watches
- If you request propagation, it does not happen immediately, but should be posted in the next day or so
This demo box is for lab 7