Agile Javaв„ў: Crafting Code with Test-Driven Development

You now have a complete context for testCreate: The first test statement creates a student with a given name, and the second statement asks for the name from the student object. All that you need do now is add a statement that will demonstrate that the student name is as expectedthat it is the same as the name passed to the constructor of the student.

public class StudentTest extends junit.framework.TestCase { public void testCreate() { Student student = new Student("Jane Doe"); String studentName = student.getName(); assertEquals("Jane Doe", studentName); } }

The third line of code (statement) is used to prove, or assert, that everything went well during the execution of the first two statements. This is the "test" portion of the test method. To paraphrase the intent of the third statement: You want to ensure that the student's name is the string literal "Jane Doe". In more general terms, the third statement is an assertion that requires the first argument to be the same as the second.

This third line is another message send, much like the right-hand side of the second statement. However, there is no receiverto what object is the assertEquals message sent? If you specify no receiver, Java assumes that the current objectthe object in which the current method is executingis the receiver.

The class junit.framework.TestCase includes the definition for the method assertEquals. Remember that in your class definition for StudentTest, you declared:

public class StudentTest extends junit.framework.TestCase {

This declaration means that the StudentTest class inherits from junit.framework.TestCase. When you send the message assertEquals to the current StudentTest object, the Java VM will attempt to find a definition for assertEquals in StudentTest. It will not find one and subsequently will use the definition it finds in junit.framework.TestCase. Once the VM finds the method, it executes it just like any other method.

The important thing to remember is that even though the method is defined in the superclass of StudentTest, it operates on the current StudentTest object. You will revisit this concept of inheritance in Lesson 6.

The third statement also demonstrates how you can pass more than one argument along with a message by using commas to separate each argument. There are two parameters to assertEquals: the String literal "Jane Doe" and the studentName reference you created in the second statement. Both represent objects that will be compared within the assertEquals method. JUnit will use the result of this comparison to determine if the testCreate method should pass or fail. If the string in the memory address referred to by studentName is also "Jane Doe", then the test passes.

Recompile and run your test. JUnit should look something like Figure 1.6.

Figure 1.6. Not Quite Done

JUnit shows a red bar and indicates one failure. It also tells you what went wrong in the first listbox:

Failure: testCreate(StudentTest): expected:<Jane Doe> but was:<>

The method failing is testCreate, located in the StudentTest class. The problem is that something expected the String literal "Jane Doe" but received instead an empty String. Who is expecting this and where? JUnit divulges this information in the second listbox, showing a walkback (also known as a stack trace) of the code that led up to the failure. The first line of this stack trace indicates that there was a ComparisonFailure, and the second line tells you that the failure occurred at line 5 in StudentTest.java.

Use your editor to navigate to line 5 of the StudentTest source code. This will show that the assertEquals method you coded is the source of the comparison failure:

assertEquals("Jane Doe", studentName);

As mentioned before, the assertEquals method compares two objects[8] and fails the test if they are not equal. JUnit refers to the first parameter, "Jane Doe", as the expected value. The second parameter, the studentName variable, references the actual valuewhat you are expecting to also have the value "Jane Doe". The studentName reference instead points to an empty String value, since that's what you coded to return from the getName method.

[8] Specifically, this example compares a String object to a String variable, or reference. Java dereferences the variable to obtain the String object at which it points and uses this for the comparison.

Fixing the code is a simple matterchange the getName method to return "Jane Doe" instead:

class Student { Student(String name) { } String getName() { return "Jane Doe"; } }

Recompile and rerun JUnit. Success! (See Figure 1.7.) There's something satisfying about seeing that green bar. Press the Run button again. The bar should stay green. Things are still goodbut not that good. Right now, all students will be named Jane Doe. That's not good, unless you're starting and all-woman school that only accepts people with the name Jane Doe. Read on

Figure 1.7. Success!

Категории