12
version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java Development and Testing: Netbeans IDE, Ant & JUnit 1. Introduction These tools are all available free over the internet as is Java itself. A brief description of each fol- lows. They are demonstrated in this example. Java 1.4.x latest version of Java. Online documentation and tutorials are also available. http://java.sun.com/ http://java.sun.com/j2se/1.4/download.html http://java.sun.com/docs/books/tutorial/ Netbeans an integrated development environment. Includes Ant. http://www.netbeans.org/ http://www.netbeans.org/ide/download.html Ant tool/classes for automated building and other tasks of software development. http://jakarta.apache.org/ant/ http://jakarta.apache.org/ant/manual/index.html JUnit tool/classes for unit testing and reporting of code during development http://junit.org/index.htm To illustrate the usage of these tools as we might want to use them in eXtreme Programming (tests are written first) we will introduce a simple example application. 2. Example Application The application supports the following stories. a. There shall be 4 states. Start, Finish and 2 intermediate states. b. The user may navigate between states by using 2 buttons, “Next” and “Back”. c. The interface will visually provide feedback about the current system state. A sketch of what the application’s Graphical User Interface (GUI) might look like follows: Start State 1 State 2 Finish Back Next > Figure 1: Sketch of application’s pro- posed user interface (GUI).

Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 1

Getting Started with Java Development and Testing:Netbeans IDE, Ant & JUnit

1. IntroductionThese tools are all available free over the internet as is Java itself. A brief description of each fol-lows. They are demonstrated in this example.

Java 1.4.x latest version of Java. Online documentation and tutorials are also available.http://java.sun.com/http://java.sun.com/j2se/1.4/download.htmlhttp://java.sun.com/docs/books/tutorial/

Netbeans an integrated development environment. Includes Ant.http://www.netbeans.org/http://www.netbeans.org/ide/download.html

Ant tool/classes for automated building and other tasks of software development.http://jakarta.apache.org/ant/http://jakarta.apache.org/ant/manual/index.html

JUnit tool/classes for unit testing and reporting of code during developmenthttp://junit.org/index.htm

To illustrate the usage of these tools as we might want to use them in eXtreme Programming (testsare written first) we will introduce a simple example application.

2. Example Application

The application supports the following stories.a. There shall be 4 states. Start, Finish and 2 intermediate states.b. The user may navigate between states by using 2 buttons, “Next” and “Back”.c. The interface will visually provide feedback about the current system state.

A sketch of what the application’s Graphical User Interface (GUI) might look like follows:

StartState 1State 2Finish

Back Next

>

Figure 1: Sketch of application’s pro-posed user interface (GUI).

Page 2: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 2

Notice that the stories are small and lack many details. The idea is that a customer is readily avail-able for the development team to meet with to work out the details. In this example we willassume all the stories should be implemented for this iteration. The first code that should be writ-ten (aside from a “spike” if necessary) are the tests which help to define what your objects shoulddo.3. Readying the basic classes

Sometimes it is hard to think about the basic objects when all you can imagine is the sketch of theGUI. However, it is commonly recognized, that the GUI and the underlying functionality are mostoften better implemented as separate but cooperating objects. The underlying functionality (oftenreferred to as the model) is independent of the particular GUI used to represent and manipulate it.We can develop the model separate from the interface. This better allows porting to different win-dow systems, development of GUI’s by trained GUI designers, better used of specialized hard-ware, etc. There are 2 immediate advantages for us: 1. Development can proceed without needingto know GUI programming; 2. Unit tests are easily automated if you don’t need to worry aboutthe GUI.

Thus we focus first on the model component. This object should be able to represent the statesrequired. It should support state transition functions and be able to respond to queries about whatstate it is currently in. We call the object type, StateModel.

Now we can begin to write tests which confirm the behavior of the model. The tests are to be writ-ten in Java using JUnit. Writing the tests within the Netbeans environment will allow Ant to auto-matically, compile, execute and generate reports about the tests.

To start, bring up Netbeans and start a new project.

a. Use the Project menu to bring up the Project Manager.b. Create a New project (the example name used is toolEx)c. Have a directory ready for your new project. Under the Netbeans Explorer you will need tomount a file system for your project. To mount your directory, use the File --> Open menu andspecify a Filesystem which is a Local Directory. Select your project directory.d. To create Java code, you will need to be ready to define what package that the code will be in.Java relates packages to directory structure so a package name will (likely) use a subdirectory ofyour project directory. The subdirectory is set up for you if you use File --> New and select theTemplate for a Java Package. We use the name cs435ex1 as the package name.

StateModel

curState: keeps current state

getState(): returns current statenextState(): go to next statebackState(): go back one state

Figure 2: The class which representsthe model for the application.

attributes

methods

Page 3: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 3

e. Finally to start creating your class source code: Select File --> New using the cs435ex1package and the class name StateModel. A Java source file is created to define the class State-Model. Of course, the details remain to be filled in.f. In addition to the basic class needed for your application, you also need to define a class whichwill carry out tests. Select File --> New using the cs435ex1 package and the class name State-ModelTester.

4. Preparing To Test

The purist approach to Test-First software development writes tests which will always fail at first.They fail because the code for the objects being tested hasn’t been written yet so the test cannotpossibly pass. Our tests will use the JUnit testing framework. Here’s a start.

/** StateModelTester.java** Created on August 10, 2002, 3:58 PM*/

package cs435ex1;import junit.framework.*;

/**** @author wainer*/

public class StateModelTester extends TestCase {

/** Creates a new instance of StateModelTester */public StateModelTester(String aName) {

super(aName);}

public static Test suite() {return new TestSuite(StateModelTester.class);

}

public static void main(String[ ] args) {junit.textui.TestRunner.run(suite());

}

public void testInitialState() {StateModel model = new StateModel();assertEquals("Check initial state", StateModel.START, model.getState() );

}}

File name also gives class name

We use the junit framework

extending the junit class TestCase

Main will run a GUI application whichperforms and displays the tests

Using reflection, tests are collected and run

Our test methods all begin with “test”

Junit provides assert methods for testing

Figure 3: A start on the StateModelTester class which uses the Junit framework totest the StateModel class.

Page 4: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 4

Of course, this test will fail to even compile since the method getState() and constant START arenot even defined. A purist approach would be to try the test and let the compiler tell you what youneed to fix. The advantage of this method is that you won’t be implementing things unless youabsolutely need them. We will go ahead and add some code to the StateModel class so at leastthings will compile. Our bare-bones implementation follows.

5. Using Ant to Compile

Netbeans, like most IDEs, can automatically compile and run the software you write. If you’vedeveloped software on UNIX systems you are probably familiar with make, an application whichreads a file of dependencies and instructions to automate development tasks. You can think of Antas a Java based make replacement.

Ant is included with Netbeans. By default, Ant’s instructions are in a file named build.xml. Indeed,the build file is in plain text with xml formatting. It may be created by Netbeans and it is recog-nized with a special icon in the Netbeans Explorer window. From that window you can run anytarget (you specify each task of interest as a target) by double-clicking on its name.

From the File --> Open window you may select an Ant build file template. If you select theempty one you will get a very small file. Replace its contents with the following.

/** StateModel.java** Created on August 10, 2002, 11:26 AM*/

package cs435ex1;

/**** @author wainer*/

public class StateModel {static final int START = 1;

/** Creates a new instance of StateModel */public StateModel() {}

public int getState() {return 0;

}

}

added to allow compilation

Figure 4: Adding just enough code to StateModel so that the first test can compile.

Page 5: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 5

Note: E:\netbeans\modules\patches\org-apache-tools-ant-module\junit.jar shown as a pathelementlocation in the build.xml file must give the path location of the junit jar file. You will need toobtain this jar file. Read the installation instructions or use the path given as an indication ofwhere it should be placed. If you do not set this up correctly, the example will fail to compile.Create your build file within your project directory not inside your package directory (cs435ex1).

Assuming your build.xml file is as above (with a proper pathelement location to the junit jar file)you should see the build.xml icon in the Netbeans Explorer window. Click the “show inside” levericon to its left, and the target compile should appear. Double-click on the compile target to makeAnt execute that task. If all goes well your code should successfully compile. The IDE will switchto the “Running” window work-set. To get back to the “Editing” work-set click its tab or use theView --> Workspaces menu selection.

6. Using Ant to Run Tests

To run the Junit tests the code first has to be compiled and then run. The build file will needanother target; we’ll call it utest. The additional text to be added is shown below. Double-click onthe utest target in the Netbeans Explorer to run the unit tests.

<?xml version="1.0"?><!-- build.xml, for Ant to compile Java sources, cs435ex1, Wainer -->

<project basedir="." default="compile"><target name="compile">

<javac debug="true" deprecation="true" destdir="." srcdir="." verbose="true" ><classpath>

<!-- gives location of junit framework objects to java compiler --><pathelement location="E:\netbeans\modules\patches\org-apache-tools-ant-module\junit.jar"/>

</classpath></javac>

</target></project>

Figure 5: An Ant build.xml file to compile the StateModel and its tester class.

Replace with the proper path location for your system

<target depends="compile" description="Execute Unit Tests" name="utest"><java classname="junit.swingui.TestRunner" failonerror="true" fork="true">

<arg value = "cs435ex1/StateModelTester" /><classpath>

<pathelement location="E:\netbeans\modules\patches\org-apache-tools-ant-module\junit.jar"/><pathelement location="."/>

</classpath></java>

</target>

Figure 6: Additional target to add to the build.xml file to enable running theJunit tests. Insert between the <project> </project> tags.

Page 6: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 6

If you were successful, you will see the Junit testing application pop-up (Figure 7). If you hadproblems, consult Figure 8 to make sure that your files are in the proper places.

7. Coding to Pass the Test

Production coding (and testing) with eXtreme Programming is to be done with Pair Programming.That aside, the tests should drive the code. We have a test that failed so we must code what isneeded to pass it. In this case, we need to maintain the state as a variable and set it properly wheninitialized. The state also needs to be accurately retrieved. See the modifications in Figure 9below. Running the utest target should now result in the test passing.

Figure 7: The Unit Test should compile and runbut as expected will fail during execution.

Figure 8: The directory structure of thefiles used in this example as shown bythe Netbeans Explorer. Double-clickingon utest should launch the testing appli-cation after making sure that the code iscompiled.

Project Directory

public class StateModel {static final int START = 1;private int curState;

/** Creates a new instance of StateModel */public StateModel() {

curState = START;}

public int getState() {return curState;

}

}

Figure 9: Adding code to so that the StateModel passes the test. Just enough code was added topass the test.

Page 7: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 7

8. Repeating the Cycle: Test Coding, Testing, Code Corrections to Pass Tests

Obviously we aren’t finished yet. Many cycles of writing tests, running tests and coding areneeded. Figure 10 shows tests for the back and next navigation methods. Figure 11 shows themodified source for StateModel so that it passes the tests.

We should make sure to test problematic areas. For example, what should happen if we try tomove back from the start state or forward from the finish state? The customer should determinewhat sort of behavior makes sense. Part of the customer responsibility is to write tests for the sto-ries. In this case, our rules will be that a “back” move from state start does nothing and a “for-

public void testBasicNavigation() {StateModel model = new StateModel();model.nextState();assertEquals("Next to State1", StateModel.STATE1, model.getState() );model.nextState();assertEquals("Next to State2", StateModel.STATE2, model.getState() );model.backState();assertEquals("Back to State1", StateModel.STATE1, model.getState() );model.nextState(); // move to state2model.nextState(); // move to finishassertEquals("Next to Finish", StateModel.FINISH, model.getState() );model.backState();assertEquals("Back to State2", StateModel.STATE2, model.getState() );

}

Figure 10: Tests for typical navigation behavior using backState and nextState methods.

public class StateModel {static final int START = 1;static final int STATE1 = 2;static final int STATE2 = 3;static final int FINISH = 4;

private int curState;

/** Creates a new instance of StateModel */public StateModel() {

curState = START;}

public int getState() {return curState;

}

public void nextState() {curState++;

}

public void backState() {curState--;

}}

Figure 11: Code to support typical naviga-tion behavior using backState and nextStatemethods and a current state variable.

Page 8: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 8

ward” move from state finish does nothing. Figure 12 shows the test code for these exceptioncases. Your test cases should make sure to cover boundary conditions and other unusual caseswhich may be encountered. As Figure 13 illustrates, the exception case tests fail.

Extreme Programming promotes the idea “You Ain’t Gonna Need It” (YAGNI). Meaning that weshouldn’t be spending a lot of effort designing for all future possibilities. The YAGNI principleoften applies since many future plans are frequently changed or cancelled. We used that principlehere to design a very simple mechanism for supporting state change.

public void testBndryNavigation() {StateModel model = new StateModel();model.backState();assertEquals("Back from Start", StateModel.START, model.getState() );model.nextState(); model.backState(); model.backState(); model.backState();assertEquals("Back again from Start", StateModel.START, model.getState() );// move from start to S1, S2, Finishmodel.nextState(); model.nextState(); model.nextState();assertEquals("Next to Finish", StateModel.FINISH, model.getState() );model.nextState(); model.nextState(); model.nextState(); // and try to move furtherassertEquals("Nexts at Finish", StateModel.FINISH, model.getState() );

}

Figure 12: Tests for navigation behavior at border conditions.

Figure 13: Earlier tests pass, butthe test for navigation at bound-ary conditions fails. The detailgives the assert statement whichcaused the failure.

public void nextState() {if (curState < FINISH) curState++;

}

public void backState() {if (curState > START) curState--;

}

Figure 14: Revising the nextStateand backState methods as showncan fix the problem. All tests nowpass.

Page 9: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 9

9. Creating and Compiling the Application and Interface

So far we have created the underlying object model and tests for that object. We need to create theactual user application which calls upon the model and supports interaction with the user. Whileprogress is being made in automatic testing tools for GUI code, we will not consider that here.

We construct a simple Swing interface for a Java application, a screen shot is shown in Figure 15.You may also use visual tools to design an interface. (Netbeans has a GUI editor. The CS Depart-ment also has Visual Cafe). In Xp you might use a “spike” to explore and experiment to quicklytest out ideas. Any code developed as part of a spike is not consider production code (It wasn’tdeveloped test-first with pair programming). It should be discarded.

Figure 15: A java application which uses Swing to pro-vide a GUI for the statemodel. As yet it is not hooked upto the StateModel code. It also fails to provide the userwith sufficient feedback since the current state is notindicated.

/** StateApp.java** Created on August 11, 2002, 2:54 PM*/

package cs435ex1;import javax.swing.*;import java.awt.*;import java.awt.event.*;

/**** @author wainer*/

public class StateApp {

JLabel startLabel;JLabel state1Label;JLabel state2Label;JLabel finishLabel;JButton nextBut;JButton backBut;

public StateApp() {}

Figure 16: StateApp.java, source code to cre-ate the application and interface shown inFigure 15.

Page 10: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 10

Figure 16 continued.public static void main(String[] args) {JFrame frame = new JFrame("Example State Application GUI");

StateApp app = new StateApp();

// Create Buttonsapp.nextBut = new JButton("Next");app.nextBut.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {// make the button click do something

}});

app.backBut = new JButton("Back");app.backBut.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {// make the button click do something

}});

// group the buttons in a JPanelJPanel buttonPane = new JPanel(); // uses default flow layoutbuttonPane.add(app.nextBut);buttonPane.add(app.backBut);

// Create the labels and have them align at their horizontal centersapp.startLabel = new JLabel("Start"); app.startLabel.setHorizontalAlignment(JLabel.CENTER);app.state1Label= new JLabel("State 1"); app.state1Label.setHorizontalAlignment(JLabel.CENTER);app.state2Label= new JLabel("State 2"); app.state2Label.setHorizontalAlignment(JLabel.CENTER);app.finishLabel= new JLabel("Finish"); app.finishLabel.setHorizontalAlignment(JLabel.CENTER);

JPanel labelPane = new JPanel(); // group the labels in a JPanel// Use a GridLayout to align the labels in a single columnlabelPane.setLayout(new GridLayout(4,1));labelPane.add(app.startLabel);labelPane.add(app.state1Label);labelPane.add(app.state2Label);labelPane.add(app.finishLabel);

// Place the buttons and labels into the frameframe.getContentPane().add(buttonPane,BorderLayout.SOUTH);frame.getContentPane().add(labelPane,BorderLayout.CENTER);frame.addWindowListener(new WindowAdapter() { // so app exits upon window closing

public void windowClosing(WindowEvent e) {System.exit(0);

}});//Finish setting up the frame, and show it.frame.pack();frame.setSize(340,300);frame.setVisible(true);

}}

Page 11: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 11

The source code for StateApp.java must be added to the project directory. To compile, build.xmlshould be modified to add another target for Ant. Insert the following to create a run target withinyour build.xml file.

10. Connecting the Application to the Model

The basic idea is to make the application act as a wrapper around the functionality of the model.The application should instantiate a model object. It queries the object and reflects the object’sstate in its interface. User interaction should be passed from the application to the model. In amore sophisticated application we would probably use a Model-View-Controller pattern. Follow-ing the YAGNI idea we just keep it simple here. The following code fragments can be added tothe StateApp source to produce the connected working application.

<target depends="compile" description="Run the Application" name="run"><java classname="cs435ex1.StateApp" failonerror="true" fork="true">

<classpath><pathelement location="."/>

</classpath></java>

</target>

Figure 17: Ant target to compile and run the application.

public void updateLabels(StateModel m) {// set all to unselected - blackstartLabel.setForeground(Color.black);state1Label.setForeground(Color.black);state2Label.setForeground(Color.black);finishLabel.setForeground(Color.black);// query the model to find and show the current stateint theState = m.getState();switch (theState) {

case StateModel.START:startLabel.setForeground(Color.red); break;

case StateModel.STATE1:state1Label.setForeground(Color.red); break;

case StateModel.STATE2:state2Label.setForeground(Color.red); break;

case StateModel.FINISH:finishLabel.setForeground(Color.red); break;

}}

model.backState(); // for back button onlymodel.nextState(); // for next button only

app.updateLabels(model);

//Make sure the true initial state is shownapp.updateLabels(model);

Figure 18: Code to add to StateApp.java to create the application and interface which utilizesthe model.

Define another method for StateApp.updateLabels is responsible for mak-ing sure that the interface reflects thestate of the model.Red letters indicate the current state.

The button handlers act on themodel and then query the model’sstate. (add to both button’sactionPerformed methods)

To make sure the initial state is visu-alized correctly, query the model’sstate. (add before frame.pack() )

final StateModel model = new StateModel();

Put “final” in front of the declarationfor app and add a line to declare amodel object.

Page 12: Getting Started with Java Development and Testing ...wainer/435F02/toolsHO.pdf · version 1.0 8/27/02 toolsExample.fm Tools H.O. CS435, M. Wainer page 1 Getting Started with Java

version 1.0 8/27/02 toolsExample.fm

Tools H.O. CS435, M. Wainer page 12

11. What Next?If automatic tests aren’t used to check the application/interface, manual tests are used. These testsmay be associated with the stories and are provided by the customer (or by closely working withthe customer to establish the tests). Developers should also get frequent feedback from the cus-tomer about the interface design and appearance. At some point, suggestions must be expressed asnew stories and the customer must make the business decisions about which stories have higherpriorities. (Fixing bugs/glitches are necessarily compared with the value of adding new features.)

12. RefactoringAfter a while, changes in code build up and you often realize that things are more complicatedthan they should be. The code is said to “start to smell” and it starts to become more error proneand difficult to maintain. Refactoring is the process of reorganizing the code. One way to tell ifrefactoring is appropriate is to notice if you have nearly identical code which repeats itself severaltimes. In our example, creating JLabels uses several calls which are nearly identical for eachlabel. A refactoring might create a new method which consolidates those calls. Figure 19 showssuch a method and how it might be used.

13. DeploymentSince it is important for your customer to run your application, you must consider how they willbe able to do this with a minimum amount of fuss. This is how to make a java application double-clickable on a Windows machine. It assumes that Java and any necessary class libraries arealready loaded. It also assumes that the PATH variable includes the java binaries directory. Italicsbelow show my values for the example application. The javaw.exe executable runs a java classfile (with a main entry point) without opening a command window.

a. Create a shortcut for the StateApp file. Place it in your project directoryb. Edit the properties of the shortcut. Change the “Target:” to run javaw

C:\WINNT\SYSTEM32\javaw.exe -classpath "." cs435ex1.StateApp

Change the “Start in:” field to your project directory.

E:\AANewJava\MyCodeTests\ToolsHO

c. Change the name of the modified shortcut to something sensible like “Run StateApp”

// add this method in StateApppublic JLabel initLabel(String text) {

JLabel lab = new JLabel(text);lab.setHorizontalAlignment(JLabel.CENTER);return lab;

}

// Creating Labels is now much simplerlabelPane.add(app.startLabel = app.initLabel("Start"));labelPane.add(app.state1Label = app.initLabel("State 1"));labelPane.add(app.state2Label = app.initLabel("State 2"));labelPane.add(app.finishLabel = app.initLabel("Finish"));

Figure 19: An example of refactoring thatapplies to StateApp. The code which cre-ates new JLabels has been simplified byintroducing a new method.