Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Thursday, March 21, 2013

Creating an Ubuntu VMware player virtual machine for Java Development

Four major steps:

  1. Install Ubuntu
  2. Install Java
  3. Instal Maven (ugh)
  4. Install git
  5. Install Eclipse
Ok, let's get to it.

Ubuntu

Create a new VM in VMWare Player and choose the iso file you downloaded from Ubuntu.  
Set memory to 2gb or you'll live in a world of pain.

Now setup VMWare tools, which won't install correctly until you follow this:
http://askubuntu.com/questions/131351/how-to-install-vmware-tools

Basically, type
sudo apt-get install build-essential linux-headers-$(uname -r)

Then install vmware tools by typing
vmware-config-tools.pl

Accept all the defaults.

Java

Installing Java is well documented as the answer at this URL:

Maven

Maven is the philosophical opposite of Ubuntu so installing it feels a bit like taking a dump on an altar, but many Java projects use it anyway.  Luckily, the install is the least painful thing about Maven (well, as long as you're not using Windows).
sudo apt-get install maven

git

Just follow the bitbucket instructions.  Easy.

Eclipse

Installing the base Eclipse is easy except for the icon.  I won't get into all the plugins you actually need to do work and the hell which can come out of that...
Download Eclipse here.
Open a terminal (click the Ubuntu logo in the upper left and type term and then click the terminal application that appears)
cd ~/Downloads
tar -xvf eclipsefilenamegoeshere.tar.gz
./eclipse &

Eclipse will now launch and a blank icon will appear in the launcher.  If you'd like to fix this, follow these instructions.


Thursday, March 15, 2012

Formatting and Parsing Java Dates

My favorite page on this topic so far is here.

Monday, March 05, 2012

Sending Multipart Form Data from Java (and receiving it via PHP)

If you want to send binary data and some parameters, you'll need to execute a POST with the content type of multipart/form-data. This takes a different format than usual HTTP requests. The secret to sending multipart form data is sending the right number of line endings. Rather than explain it, here's the code.
String lineEnd = "\r\n"; 
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
File temp_file = new File("foo.txt");
// open a URL connection
URL url = new URL(urlString);

// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();

// Allow Inputs
conn.setDoInput(true);

// Allow Outputs
conn.setDoOutput(true);

// Don't use a cached copy.
conn.setUseCaches(false);

// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);

dos = new DataOutputStream( conn.getOutputStream() );

// Send parameter #1
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"param1\"" + lineEnd + lineEnd);
dos.writeBytes("foo1" + lineEnd);

// Send parameter #2
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"param2\"" + lineEnd + lineEnd);
dos.writeBytes("foo2" + lineEnd);

// Send a binary file
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + temp_file.getName() +"\"" + lineEnd);
dos.writeBytes(lineEnd);

// create a buffer of maximum size

bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];

// read file and write it into form...

bytesRead = fileInputStream.read(buffer, 0, bufferSize);

while (bytesRead > 0)
{
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}

// send multipart form data necesssary after file data...

dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

// close streams
fileInputStream.close();
dos.flush();
dos.close();


Ok, now how to read this on the other end? Here's how to do it via PHP:
// Make sure a binary file is attached to the POST
if(!$_FILES) {
echo "No file!"
}

$id = $_FILES['uploadedfile']['name'];
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], "/permanent/location".$id);

// Uncomment next line to print out the array to a file
// file_put_contents("/permanent/location/".$id.".debug.txt", print_r($_POST, true));
$param1="";
$param2="";
if(isset($arguments['param1'])) {
$lat = $arguments['param1'];
}
if(isset($arguments['param2'])) {
$lon = $arguments['param2'];
}
echo "Uploaded " . $id . " with param1=" . $param1 . " and param2=" . $param2;

Android ProgressDialog and Threads

Many tasks require an application to get or post data from/to some web service. Since internet communication can be quick or quite lengthy, it's necessary to notify the user that some work is occurring. Android's ProgressDialog gives you two options: a dialog with a bar (like a copy dialog on Windows) or a spinner dialog (typical for Ajax web apps).

Unfortunately, using the progress dialog can be painful. Frustratingly, many tutorials show you how to instantiate a ProgressDialog but not how to use it properly, failing to mention that if you make a blocking call on the UI thread (like an HTTP request), the ProgressDialog will never actually appear. After 2 seconds, the Android OS will think your app has frozen and kill it. Great.

Many forum posts suggest using Android's AsyncTask to execute the "work" in the background (AsyncTask is supposed to be easier to use than creating a new thread), but I've found AsyncTask to be more headache than help. Just create a thread. It's not hard.

FYI, ProgressDialog requires a context (the calling activity), a message to display, and a handler to do some work. Your handler can only receive ONE variable, so I tend to use a HashMap so I can pass multiple bits of data.

I've come up with a pattern that I've reused and works well. Here we go!

  1. Create a thread class.

  2. public class WorkerThread extends Thread {
    private ProgressDialog dialog;
    private Handler handler;
    private HashMap messageData = new HashMap();

    // .. put your constructor etc here ...
    public WorkerThread(ProgressDialog dialog, Handler handler) {
    this.dialog = dialog;
    this.handler = handler;
    }

    public void run() {
    // Var to keep track of whether the work succeeded or not
    Boolean status = true;
    // ... do some work here ...

    // If an error occurred...
    if(error) {
    status = false;
    messageData.put("message", "Error message goes here");
    }
    messageData.put("status", status);

    // Send a message back to calling activity
    handler.obtainMessage(0x2a, messageData).sendToTarget();

    // Dismiss dialog
    if (dialog != null && dialog.isShowing())
    dialog.dismiss();
    }

    // Clean up if the thread is cancelled
    public void cancel() {
    messageData.put("status", false);
    handler.obtainMessage(0x2a, messageData).sendToTarget();
    if (dialog != null && dialog.isShowing())
    dialog.dismiss();
    }
    }
  3. Add a thread and a null handler to your activity.
  4. WorkerThread WorkerThreadInstance = null;
    Handler handler = null;
  5. Create the ProgressDialog in your Activity's onCreate

  6. ProgressDialog workDialog = ProgressDialog.show(this, "", "Working...", true);
  7. Create a handler.

  8.   // Handle response from the worker thread
    handler = new Handler() {
    @SuppressWarnings("unchecked")
    @Override
    public void handleMessage(Message msg) {
    super.handleMessage(msg);
    HashMap data = (HashMap) msg.obj;
    Boolean status = (Boolean) data.get("status");

    if (status==true) {// if successful
    Toast.makeText(getApplicationContext(), "Work was successful",
    2000).show();
    // Process return data here
    // Uncomment the next line if your activity should end once processing is done
    //finish();
    } else {
    if(data.get("message")!=null) {
    Toast.makeText(getApplicationContext(), "Work failed!" + data.get("message") ,
    3000).show();
    }
    // Uncomment the next line if your activity should end after an error
    //finish();
    }
    }
    };
  9. Instantiate your worker thread

  10.   // Create an instance of the worker thread
    WorkerThreadInstance = new WorkerThread(workDialog, handler);
    WorkerThreadInstance.start();
  11. Implement onPause for your activity to stop the worker thread if the activity is paused(and possibly onResume-- though be aware that onResume will be called before onCreate)

  12.  @Override
    public void onPause() {
    super.onPause();

    if (WorkerThreadInstance != null) {
    WorkerThreadInstance.cancel();

    // Mark thread for deletion by GC or there will be a memory leak
    WorkerThreadInstance = null;
    }
    }

Android ListView

Android includes a ListView element designed to make it easy to create lists. But it's not as straightforward as adding a ListView element and then calling some add function. You will need to create an "ArrayAdapter" and a couple of layout XML files, unless you want to create a simple list of strings (change your activity from extending Activity to ListActivity and use the default array adapter).

Rather than explain the process, I refer you to a great tutorial which be found here.

Friday, September 17, 2010

"FriendFeed" Model Schema-Less Data Storage

Modern application developers face a challenge ill-suited to traditional RDBMS'. The data collected by applications is a moving target, with additional data points added often as applications mature. Also, many applications aggregate data from multiple sources where data points captured may differ or change beyond the control the application developer. Traditional RDBMS and the tools and checks built into those tools prefer static schemas. For example, Netbeans has a wizard to create Java entity beans from tables, but no simple way to update the entity beans when the schema changes. While creating the bean can take 5 minutes, adding a column takes hours. What's an architect to do?

One solution is to stuff an entire record into a LOB column in a traditional RDBMS (or whatever the equivalent of the LOB is in the particular RDBMS). This, however, makes indexing difficult.

Oracle has built in libraries to allow indexing and searching of XML data in BLOB and CLOB columns, but the performance is poor (though better than extracting the whole LOB and parsing it in, say, Java). Columns for indexing could be added to the LOB table, however if additional indexes are needed at a further date, the table schema must be altered.

The solution is to the indexing problem is to create separate tables for each index. Details of how this was accomplished at FriendFeed can be found here.

Note also, that if value comparison searches are not needed, a persistent hash map like Project Voldemort can be used instead.

Monday, March 08, 2010

Install Android 2.1 USB Device Driver on Windows 7 64 bit

Windows 7 64 bit has difficulty installing the current USB drivers for Android devices. You'll need these to actually test Android applications on a phone.

Feel free to poke around Control Panel for an hour trying to force it to recognize the drivers sitting on your hard drive. It simply won't comply.

Luckily there is an easy work around-- install PDANet. You can remove the program after installation-- it will leave the drivers behind.

See:
http://forum.xda-developers.com/showthread.php?t=502010&page=22
http://androidforums.com/motorola-droid/35877-cant-get-tether-work.html

Tuesday, January 12, 2010

Netbeans and Tomcat: Shared Memory Realm problems when Tomcat is started in Debug Mode

Tomcat and Netbeans don't play nice. Everything starts out well, but the situation goes downhill every time the application is deployed, usually necessitating killing of Tomcat's JVM after a few deploys.

Finally I ran into a show stopper. It always goes away, yet I don't know what action causes it to go away, and then it comes back again later. The exact error was:

ERROR: transport error 202: failed to accept shared memory connection: stream closed

It only happens when Tomcat is started via Netbeans in debug mode. Sometimes there would be no error but no breakpoints were ever triggered.

How to fix it? Don't use a shared memory realm for debugging. The Netbeans and Tomcat JVM need some way to communicate during debugging and Netbeans provides two methods.

Go to services. Expand Servers and right click on Tomcat. Choose properties and select the startup tab. Change the radio button from Shared Memory Name to Socket Port. Kill Tomcat and start it in debug mode. Voila.

Wednesday, October 28, 2009

Use c3p0 connection pooling with JPA

Add the following to your POM:


<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>3.3.2.GA</version>
</dependency>

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-tools</artifactId>
<version>3.2.3.GA</version>
</dependency>

<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>

Add the following to your persistence.xml:


<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.timeout" value="300"/>
<property name="hibernate.c3p0.max_statements" value="50"/>
<property name="hibernate.c3p0.idle_test_period" value="300"/>

You can verify c3p0 is working by using jconsole (in your java/bin) and connecting to your running Tomcat instance. If jmx isn't enabled, you can enable it by providing the following JAVA_OPTS in catalina.sh:

-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=3000
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Friday, October 02, 2009

Quickly Load Values from a Properties File

import java.util.ResourceBundle;
...
// Next line loads myFile.properties from the application's WEB-INF/classes directory
ResourceBundle resourceBd = ResourceBundle.getBundle("myFile");
String foo = resourceBd.getString("foo");

That's it! All you need is myFile.properties with the following contents:
foo=bar

Wednesday, September 16, 2009

Using Oracle Sequences with JPA

Oracle doesn't allow auto increment like MySQL. Auto increment, on big applications can cause all sorts of problems. Most JPA examples are targeted for MySQL.

First, I use Number(19) for id columns.

Second, the generator name is not important so long as it is unique and generator in GeneratedValue annotation matches name in SequenceGenerator annotation.

Sequence Name in SequenceGenerator is the name of your Oracle sequence.

Example entity code:

import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.SequenceGenerator;
...
@Id
@Basic(optional = false)
@Column(name = "MY_ID")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "MYNOTIFSEQ")
@SequenceGenerator(name="MYNOTIFSEQ", sequenceName = "MY_SEQ")
private Long userNotificationId;
...


Here's a sample sequence:
------------------------------------
--
-- Sequence MY_SEQ
--
------------------------------------
CREATE SEQUENCE MY_SEQ
INCREMENT BY 1
START WITH 1
MINVALUE 1
MAXVALUE 999999999999999999
NOORDER
CACHE 20
CYCLE
/

Loading a Properties File in a Java Application

Most of the examples I found only rely on servletContext, but this is no use if you aren't using a servlet. Also, there is a quick approach using ResourceBundle, but that approach is limited in how you can load the properties file.

Properties tempProps = new Properties();
try {
URL startupPropsURL = this.getClass().getClassLoader().getResource("/test.properties");
File startupPropsFl = new File(startupPropsURL.toURI());

try {
InputStreamReader aRdr = new InputStreamReader(new FileInputStream(startupPropsFl));
tempProps.load(aRdr);
aRdr.close();
} catch (Throwable e) {
System.out.println("Error occured while trying to load test.properties ");
e.printStackTrace();
}

System.out.println("Getting log files from "+tempProps.getProperty("foo.baseURL"));
return tempProps.getProperty("foo.baseURL");
} catch (Throwable ex) {
System.out.println("Error occured while trying to read from log.properties ");
ex.printStackTrace();
}

Friday, September 11, 2009

Running Java Code when a Web App Starts or Stops

You can run Java code when a web application starts and stops by implementing ServletContextListener in your class. ServletContextListener requires two methods (an init and a destroy) and an entry in web.xml configuring the listener.

If you like, you can persist data beyond the initialization by creating static variables in your class.

See details here: http://www.java-tips.org/java-ee-tips/java-servlet/how-to-work-with-servletcontextlistener.html

Here's a quick version

package org.peter;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;

public class ServletListener implements ServletContextListener {

private ServletContext context = null;
static ArrayList lf = null;

/*This method is invoked when the Web Application has been removed
and is no longer able to accept requests
*/
public void contextDestroyed(ServletContextEvent event) {
//Output a simple message to the server's console
System.out.println("The web app has been removed");
this.context = null;
}

//This method is invoked when the Web Application
//is ready to service requests
public void contextInitialized(ServletContextEvent event) {
this.context = event.getServletContext();
System.out.println("Web app started up");
lf.add("foo");
} // end of Initialized
}


And the entry in web.xml:
<listener>
<listener-class>
org.peter.ServletListener
</listener-class>
</listener>

Set a limit on the size of a LinkedHashMap

LinkedHashMap allows you to override the removeEldestEntry function so that whenever a put is executed, you can specify whether to remove the oldest entry or not, thus allowing implementation of an LRU.

LogMessages = new LinkedHashMap<Long,String>() {
protected boolean removeEldestEntry(Map.Entry eldest) {
if(this.size()>10000)
return true;
else
return false;
}
};

Tuesday, September 08, 2009

Tuning ehcache and hibernate

Hibernate mapping files are mapped to cache "regions" and each region has some configuration options that is configured in the ehcache.xml. A simple strategy for tuning is to create three different classes of objects:

  1. short lived entities
  2. long lived, but not eternal entities
  3. eternal entities
Which class does your entity fit into? Eternal entities will never change while your system is running. Long lived entities are accessed repeatedly, for example by a logged in user, for an extended period of time. Most other objects are short lived, and usage is confined to a relatively short period of time, perhaps across only a handful of transactions.

The number of elements stored in a cache region will vary by your application and the entity.

Short Lived Entity
Notice that the time to live is on the order of seconds to a few minutes
<cache
name="myregion"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="30"
timeToLiveSeconds="120"
overflowToDisk="false"
diskSpoolBufferSizeMB="0"
maxElementsOnDisk="0"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="0"
memoryStoreEvictionPolicy="LRU" />


Long lived Entity
Notice that the time to live is on the order of minutes to hours
<cache
name="myRegion"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="3600"
overflowToDisk="false"
diskSpoolBufferSizeMB="0"
maxElementsOnDisk="0"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="0"
memoryStoreEvictionPolicy="LRU"
/>



Eternal Entity
Time to live is set to 0 so that the cache entries persist forever.
<cache
name="myRegion"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
diskSpoolBufferSizeMB="0"
maxElementsOnDisk="0"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="0"
memoryStoreEvictionPolicy="LRU"
/>


Verifying your Settings
Well with the above information you can make some pretty good guesses, but you can actually check how well things are working using JConsole.

JConsole can connect to Tomcat instances and cache statistics can be monitored. You must configure Tomcat to open a port for JConsole to connect. Add the following to Catalina OPTS in your startup script:

-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1612 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.snmp.port=16666 -Dcom.sun.management.snmp.acl=true

You will also have to configure a management bean for your application. For Spring applications, you can use the following XML:

<!-- Stuff for hibernate and ehcache mbeans -->

<bean id="ehCacheMBeanRegistration"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">

<property name="staticMethod"
value="net.sf.ehcache.management.ManagementService.registerMBeans"/>
<property name="arguments">
<list>
<ref bean="cacheManager"/>
<ref bean="mbeanServer"/>
<value>true</value>
<value>true</value>
<value>true</value>
<value>true</value>
</list>
</property>
</bean>

<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true"/>
</bean>

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
<property name="shared" value="true"/>
</bean>

<!-- end of stuff for hibernate and ehcache mbeans -->


Now start Tomcat.

Navigate to your JDK's bin directory. Type jconsole tomcat_hostname:port.

A dialog will appear asking you to login. Enter username/password credentials (configured in Tomcat_home/conf/tomcat-users.xml -- connect as a user with the manager role).

Navigate to the MBeans tab.

Expand net.sf.ehcache

Expand cachestatistics

There will be one more sub folder within which your regions will be listed. Each region will have a set of Attributes. You can monitor cache hits and misses and tune your settings to minimize the number of misses.

Thursday, September 03, 2009

How to Debug Hibernate Mapping Problems

If you are using Hibernate in Tomcat with XML configuration files (rather than annotations) you probably have had an instance where there was a problem with a mapping file and Tomcat will not start correctly. The catalina log will show the mappings being loaded over and over again. Since there is no clear order to what will be loaded next, it's not possible to tell which file is causing the issue.

What you can do on a UNIX system is install strace. strace will show you all the system calls being executed by a process. You can attach strace to a running process and log output and then inspect which file Tomcat loaded (if you're lucky, there will be a SEGFAULT or some other problem). The mapping files be loaded over and over again, so you just need to find where they start to loop and the last mapping is the one that is causing the problem. To do that, you can find the first mapping file that is loaded and simply search in the log for the next occurrence. Scroll up and you'll find the culprit.

Step by step:
  1. Start Tomcat
  2. Press CTRL-Z to suspend Tomcat
  3. ps -ef | grep juli to find all instances of Tomcat; note down the PID (usually the first of two similar, adjacent numbers)
  4. Execute "bg 1" to resume execution of Tomcat
  5. Execute "strace -fF -p YOUR_PID_HERE &> strace.log" to trace Tomcat
That's it... good luck!

Thursday, July 23, 2009

Iterating Collections in Java

There are a number of ways to iterate over Collections. The old and tedious method is to use iterators and a for loop or while hasNext(). In recent years you can instead use an EntrySet.

Here's a pretty good sampling of the methods available:

http://hanuska.blogspot.com/2006/08/improved-map-iteration_13.html

And my own iteration over a set:

// assumes Map<String, String> stuffAttributes exists in scope
Set<Stuff> attributes = new HashSet<Stuff>();
Boolean success = true;

for (Map.Entry<String, String> prmEntry : stuffAttributes.entrySet()) {
StuffAttribute attribute = new UserNotificationsAttribute();
attribute.setAttributeKey(prmEntry.getKey());
attribute.setAttributeValue(prmEntry.getValue());
if (!attributes.add(attribute)) {
success = false;
}
}
un.setStuffAttributeSet(attributes);

Getting Request and Response objects in a Struts Action Class

Basically, you need to make your action class implement two interfaces-- ServletRequestAware, ServletResponseAware, add an HttpServletRequest and HttpServletResponse object, then implement the necessary getters and setters for each.

See full code:
http://www.roseindia.net/struts/struts2/strutsresources/access-request-response.shtml

Friday, April 10, 2009

Tomcat's Catalina base and Catalina home

Sometimes you see references to tomcat/catalina home and tomcat/catalina base.  What's the difference.  The answer comes from Alessandro A. Garbagnati who writes:

"The first properties (catalina.home) points to the location of the common information, while the other property (catalina.base) points to the directory where all the instance specific information are held."

Basically, this way you can keep one copy of the Tomcat binaries yet use a different configuration by changing the directory to which base points (this directory must contain conf, logs, webapps, work, and temp).

Thursday, January 15, 2009

Getting Started with JUnit

I'm going to skip installation. Eclipse EE has it built in; and you can Google how to install JUnit too.

JUnit makes unit testing of Java classes pretty easy. The idea is to actually write your tests before you start coding based on written specs, but you can also do it afterwards too. Good unit testing should make it easy to change code with confidence. It's also something you can hand to your boss to say "my code works."

Load up Eclipse and make sure the Package Explorer is open.
  • Right Click on a class, then New, JUnit Test Case
  • Make sure the checkboxes for generating setUp and tearDown
Here's how it works:
  • setUp() will be run once at the start of your test. In it you should create an instance of your object. You can declare a variable to hold your object inside the JUnit test case (like private myObjectsName = null).
  • Eclipse automatically makes a stub function for each function in your class-- for example, getName() will have a corresponding testGetName() function
  • You fill out each stub. Remove fail("Not yet implemented") and replace using normal Java code and the macros listed at the following URL (scroll down a bit to all the assert and fail macros):
    http://open.ncsu.edu/se/tutorials/junit/
  • Right click on your JUnitTestCase-- it should be YourObjectNameTest.java-- Run As, JUnit Test (or you can do Debug As instead)
  • The result will be a new pane in Eclipse called JUnit. It will list all the test functions and put an icon next to them indicating if they were successful or if they errored out or failed.
I found assertTrue and assertEquals to be the most useful.

As an example, you could test a get function by using assertEquals to check that the value of the attribute is the same as what you set it to be in Setup. To test a set function, set the value to something else and then assertEquals that the return value is the new value (don't forget to set the value back).

    public void testSetPatientid() {
myObject.setStuff(2); // set a new value
assertEquals("Stuff is incorrect", new Integer(2), (java.lang.Integer) myObject.getStuff()); // check that it's right
myObject.setStuff(1); // set it back
}


Some things are a bit more tricky. For example, I used assertTrue to check that the return of a function was of the right type-- assertTrue("message", myObject.getSomething() instanceof org.blah.blah.Stuff)

For more info, look at:
http://clarkware.com/articles/JUnitPrimer.html

Labels

Blog Archive

Contributors