Refresher on JUnit, and Debugging in Eclipse
Overview
Debugging is hard. And it can be pretty annoying. If you've written a test and it's failing, how do you know where to look to fix it?Fortunately Eclipse has a powerful debugging mode for this exact purpose (go figure)! If you know how to use it, Eclipse's debugger can make your coding life much easier. In this lab, we will go over some tree examples (which should be fairly familiar after last week's homework) and give an overview of the Eclipse Java debugger.
JUnit Testing
Before we get to the debugger, we will quickly review JUnit Testing. You've used JUnit Tests in 120, but if you're a little rusty, hopefully some more practice can help!Download the lab, and get it set up in Eclipse. Remember, when you're creating your project, on the Java Settings screen, select the Libraries tab, Add Library, JUnit 4. Import all the files, and open up FigureApp.java.
We've provided an implementation of Polygon and its boundingRectangle() method, from HW1, in FigureApp. Look over the code we've given you - this is what a good sample solution (for the given parts of the assignment) would look like. Now look over the bounding rectangle method. This is the method we will be testing. Right click on the project, choose New -> JUnit Test Case. Name it "BoundingRectangleTest". Select "setUp()" where Eclipse asks about method stubs - the setUp() method gets called before every test case. For Class under test, click Browse and choose FigureApp, and then hit Next.
For this example, just select FigureApp for test methods. In most situations, Eclipse will actually allow you to select the methods you will be testing, and create test methods that get run before each of their corresponding methods. However, since the FigureApp setup is a bit unconventional, such that the method we really want to test is within a class inside FigureApp, that setup doesn't work.
Eclipse creates two test methods for you, setUp() and test(). Create a global variable for your FigureApp, and instantiate it in setUp(). In test(), add a test which tests basic functionality of boundingArea(). Use the assertEquals() method to check the bounding area of a (non-right) triangle, and once you've written your test, right click on BoundingRectangleTest in the Package Explorer, and choose Run As -> JUnit Test.
Not so coincidentally, the test fails. It may already be clear to you why it's failing, but for the sake of this example, we will jump into the execution of the code, using the debugger, to try to figure that out.
Running the Debugger
The Eclipse debugger allows us to set "breakpoints" at lines, where we can pause the code and see exactly what's going on, step by step. You might have accidentally set some of these by double clicking on the bar to the left of the code (where the line numbers are). This time we'll put a break point in intentionally.Add a breakpoint to the first line in your test method. You can do this by either doubleclicking on the bar immediately to the left of the code, or right clicking on the bar and selecting Toggle breakpoint. (Toggling means inserting or removing a breakpoint, disabling means leaving a breakpoint at a particular line but temporarily disabling it).
Once you have set the breakpoint, run BoundingRectangleTest in debug mode. You can do this by right clicking on BoundingRectangleTest.java in the package explorer, selecting "Debug As" (right under "Run As"), and selecting JUnit Test. A window should pop up asking to switch perspectives. Select OK. (you can always switch back to your default Java perspective by selecting Java in the upper right corner). The code should execute up to the breakpoint, and the line with a breakpoint should be highlighted in green.
The code has at this point stopped and you can control the execution. Your primary method of control are the three buttons here:
; Step Into, Step Over, and Step Return.
These controls are largely self-explanatory. Step into will dive into any method(s) being called on that line. Step over will move to the next line of code (executing everything on that line). Step return will jump out of the current method, up the call stack. You can see the current call stack in the text below the buttons. When the debug mode starts executing, we are in BoundingRectangleTest.test(), and you can see which methods were called through the inbuilt Java-JUnit-code in the call stack above test(). If you clicked Step return, we would jump back into the execution of NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) - which we don't care about. (And step into functions like the opposite of step return. Step return pops off a method from the call stack, and step into pushes the highlighted method on).
In this case, we want to step over the first few lines of the test, until we get to the line that calls boundingArea. Once that line is highlighted, click step into (note: if you ever accidentally jump too far past the code you wanted to step into, you can just click the red square button to stop the test, and re-run the test by clicking the button to the left of Run with a bug on it). Notice, when you click on step into, FigureApp.boundingArea() gets added to the stack trace. In addition to the stack trace, you should have a Variables section of your window, which looks like this:
This section shows you all your current variables, and their values. This can really come in handy if there are complicated things being done to modify variables in your code! By stepping over into the next line of boundingArea(), you should be able to look at the different values of the bounding rectangle in the Variables window. That should show you what's going on with the incorrect value being returned for the area. Re-run the tests, and this time when you are at the first line of boundingArea(), choose Step Into again to go into step by step execution of Polygon.boundingRectangle(). Play around with the debugger until you figure out what's going wrong in setting up the bounding rectangle, and once you've done that, go ahead and make the fix in the code.