1 of 2

Name:

PID: (page 1)

Debuggers would be more accurately called program or process inspectors.

They don't actually remove any bugs. You (the programmer) have to do that. They tell us what's going in the running program so we can relate symptoms to our code. They also let us see some information that's often hidden away, like private fields or memory layout information.

interface StrChecker { boolean checkString(String s); }

class ListEx {

private static List<String> result = new ArrayList<>();

// Returns a new list that has only the elements of the

// input where the given StringChecker returns true

static List<String> filter(List<String> list, StrChecker sc) {

if(list.size() == 0) { return list; }

result.clear();

for(String s: list) {

if(sc.checkString(s)) {

result.add(s);

}

}

return result;

}

}

  1. import static org.junit.Assert.*;
  2. import org.junit.*;
  3. import java.util.Arrays;
  4. import java.util.List;
  5. class IsA implements StrChecker {
  6. public boolean checkString(String s) {
  7. return s.equalsIgnoreCase("a");
  8. }
  9. }
  10. public class TestListExamples {
  11. @Test
  12. public void testFilter() {
  13. List<String> s1 = Arrays.asList("a", "b", "c");
  14. List<String> s2 = Arrays.asList("d", "a");
  15. List<String> expect = Arrays.asList("a");
  16. List<String> result1 = ListEx.filter(s1, new IsA());
  17. List<String> result2 = ListEx.filter(s2, new IsA());
  18. assertEquals(expect, result1);
  19. assertEquals(expect, result2);
  20. }
  21. @Test
  22. public void testFilter2() {
  23. List<String> s1 = Arrays.asList("a", "b", "c");
  24. List<String> s2 = Arrays.asList("d", "a", "a");
  25. List<String> expect1 = Arrays.asList("a");
  26. List<String> expect2 = Arrays.asList("a", "a");
  27. List<String> result1 = ListEx.filter(s1, new IsA());
  28. List<String> result2 = ListEx.filter(s2, new IsA());
  29. assertEquals(expect1, result1);
  30. assertEquals(expect2, result2);
  31. }
  32. }

$ java -cp .:lib/* org.junit.runner.JUnitCore TestListExamples

JUnit version 4.13.2

.E.

Time: 0.011

There was 1 failure:

1) testFilter2(TestListExamples)

java.lang.AssertionError: expected:<[a]> but was:<[a, a]>

at org.junit.Assert.fail(Assert.java:89)

at org.junit.Assert.failNotEquals(Assert.java:835)

at org.junit.Assert.assertEquals(Assert.java:120)

at org.junit.Assert.assertEquals(Assert.java:146)

at TestListExamples.testFilter2(TestListExamples.java:39)

FAILURES!!!

Tests run: 2, Failures: 1

Which assert/test is failing?

What's your best guess as to why? What's weird about the code in ListEx?

How many Lists do you think are created during that test? What's their contents and which variables or fields refer to them?

2 of 2

Name:

PID: (page 2)

$ javac -g -cp .:lib/* *.java -g is a special option that adds information for the debugger to the class files

jdb (Java Debugger) runs much like the java command, but when it starts up it gives a special prompt that lets us control evaluation

$ jdb -classpath .:lib/* org.junit.runner.JUnitCore TestListExamples (detail: -classpath not -cp)

Text on line after > are what I typed, the rest is the response. It's a special kind of “debugging shell”

stop at is a command that means "when you get to line 35 in TestListExamples, stop and let me run inspection commands”

> stop at TestListExamples:39

Deferring breakpoint TestListExamples:39.

It will be set after the class is loaded.

the program doesn't actually start running until we use the command “run”

> run

run org.junit.runner.JUnitCore TestListExamples

Set uncaught java.lang.Throwable

Set deferred uncaught java.lang.Throwable

>

VM Started: JUnit version 4.13.2

Set deferred breakpoint TestListExamples:39

.

Breakpoint hit: "thread=main", TestListExamples.testFilter2(), line=39 bci=104

39 assertEquals(expect1, result1);

here, the program is STOPPED, right before running line 39 (the line with the failing assert). Now we can inspect current values of variables, fields, and so on. The prompt looks a little different, too.

main[1] print s1

s1 = "[a, b, c]"

main[1] print s2 you fill in the blanks here – what's the current value?

main[1] print result1

main[1] locals

Method arguments:

Local variables:

s1 = instance of java.util.Arrays$ArrayList(id=717)

s2 = instance of java.util.Arrays$ArrayList(id=720)

expect1 = instance of java.util.Arrays$ArrayList(id=722)

expect2 = instance of java.util.Arrays$ArrayList(id=723)

result1 = instance of java.util.ArrayList(id=724)

result2 = instance of java.util.ArrayList(id=724)

main[1] print ListExamples.result (view a private field!)

ListExamples.result = "[a, a]"

(partial) output of help for jdb

run [class [args]] -- start execution of application's main class

where [<thread id> | all] -- dump a thread's stack

print <expr> -- print value of expression

dump <expr> -- print all object information

eval <expr> -- evaluate expression (same as print)

set <lvalue> = <expr> -- assign new value to field/variable/array element

locals -- print all local variables in current stack frame

stop at <class id>:<line> -- set a breakpoint at a line

catch [uncaught|caught|all] <class id>|<class pattern>

-- break when specified exception occurs

step -- execute current line

next -- step one line (step OVER calls)

cont -- continue execution from breakpoint

list [line number|method] -- print source code

javac -g ... compile options ...

Compile a java program with debugging information

java -classpath ... ClassName args ...

Run the java debugger, and use commands to the left to control and inspect

What's interesting about this locals output? How does that relate to what we noticed was weird on the front?