Student: Professor, my fingers and eyes are tired.
Prof: You should get some rest!
Student: No, I mean that I’m annoyed at how much typing and reading something is taking in my program. Can you help me make it shorter?
Prof: Oh, I see. Show me what’s going on.
Student: Well, I wrote a cool method, I think, to calculate the difference between two times. I wanted to use
main like you showed me. There are two things I don’t like. One is all the times I have to type System.out.println (I know I can get AI to do it for me, but I feel like the practice is good). But the other is that it’s hard for me to check the output by reading it. Here’s my code:Prof: I see. So it’s printing out all these times and you don’t know which is which?
Student: Right – I see all the numbers, but like… I lose track. And I also tried a version that made 12 separate definitions with like
int shouldBe90 = ..., but that didn’t help that much.Prof: First of all, great job. You’re doing the right thing by checking your work, and you’re making a great observation here. Think about how bad this would get if you had a dozen methods like this! Printed output isn’t the right way to check things once programs get large.
Student: Yeah how do big companies manage this? They have tons of code, right?
Prof: Right! So the main thing people use here is something that:
- Checks a result from our program against an expected result. These are called test assertions or just tests
- Only prints or reports when things fail. That’s called a test harness or a test runner
The standard one for Java is called JUnit. The book runs a simplified version. The main function we need is assertEquals:
void assertEquals(value1, value2)
It’s somewhat special in that it can take and compare any two values (which is why for now I didn’t give them any type). It reports an error if the values aren’t equal, and does nothing if they pass.
Here’s what it looks like for just two tests of your minutesBetween method:
Prof: Notice how the first value (90) is the expected value that we wrote out by hand (or copied from somewhere).
Student: But it didn’t print anything!
Prof: Right! That was kind of the goal, right? No noise if everything went well. But I agree that it can be jarring to see nothing. One thing we can do, for our book examples, is put one print statement to see that we got to the end.
Prof: Now we know we got to that line if we see it, and can rest easy knowing our tests succeeded. Now try writing a test that fails!
Student: Like this?
Student: Oh cool! It doesn’t print the “all succeeded” message this time, and says what failed.
Prof: Right, so that’s what it looks like when the expectation (which you wrote as
1, good work) doesn’t match the actual value the method gives back (which is 0). In this case, we just did that to see what would happen. In big programs, the usual idea is that the expected result is what you carefully check yourself, and then the assertion makes sure that your program did what you expect.Student: Got it. So I can use
assertEquals, which will check something about my program and only report it if something went wrong.Prof: Exactly, and that’s a critical tool for having confidence in our programs; seeing the assertions succeed tells us a lot about what our program did!
Practice
Work out by hand how many seats each course has left, and write that as the expected value of its test.
record Course(String name, int maxEnrollment, int enrollment) {
int seatsAvailable() {
return maxEnrollment - enrollment;
}
}
void main() {
assertEquals(, new Course("CSE 11", 400, 385).seatsAvailable());
assertEquals(, new Course("CSE 12", 200, 200).seatsAvailable());
System.out.println("All tests succeeded!");
}
int seatsAvailable() {
return maxEnrollment - enrollment;
}
}
void main() {
assertEquals(, new Course("CSE 11", 400, 385).seatsAvailable());
assertEquals(, new Course("CSE 12", 200, 200).seatsAvailable());
System.out.println("All tests succeeded!");
}