Testing with Live Devices
In a lot of the projects I work on the software we write must communicate with other live devices that speak a variety of protocols and testing using mock objects will only get you so far. That is why I like to capture actual data that is coming out of these devices and include it directly in my unit tests.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public class ByteArrayUtils { private ByteArrayUtils() {} public static byte[] fromHexString(final String encoded) { if ((encoded.length() % 2) != 0) throw new IllegalArgumentException("Input must contain " + "an even number of characters"); final byte result[] = new byte[encoded.length()/2]; StringBuffer buf = new StringBuffer(encoded); for (int i = 0; i < buf.length(); i += 2) { result[i/2] = (byte) Integer.parseInt(buf.substring(i, i+2), 16); } return result; } public static String toHexString(byte[] data) { if (data == null) return ""; StringBuffer buf = new StringBuffer(data.length * 2); for (int i = 0; i < data.length; i++) { String ch = Integer.toHexString(data[i] & 0xff); if (ch.length() == 1) { buf.append("0"); } buf.append(ch); } return buf.toString(); } } |
Using this class allows me to convert byte arrays into strings that I can then include directly in my unit test cases. You can then inject the byte array into you code, and its just like having the real device there (well sorta)
Tivo Detection: Network Discovery
I’m sure that you know if you have a Tivo or not, but I’m providing a class based on the “Tivo Connect Automatic Machine Discovery Protocol Specification” that will listen for the Tivo UDP heartbeat and provide a notification when the heartbeat is detected.
Usage:
1 2 3 4 5 6 7 | TivoLocator.getInstance().addListener(new TivoLocatorListener() { public void processTivoHeartbeat(TivoInformation info) { System.out.println("Tivo IP: " + info.getAddress()); } }); |
The Tivo will send out these hearbeats about every 60 seconds or so. The TivoInformation class will tell you information such as:
Internet Address: getAddress()
Connect Method: getMethod()
Platform: getPlatform()
Machine Name: getMachineName()
Identity: getIdentity()
Services: getServices()
Software Version: getSwVersion()
Code: TivoLocator.java
Spec: TivoConnectDiscoverySpec.pdf
Computing Levenshtein Distance in Java
The Levenshtein distance between two strings is given by the minimum number of operations needed to transform one string into the other, where an operation is an insertion, deletion, or substitution of a single character.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | public class LevenshteinDistance { private static int minOfThree(int a, int b, int c) { return Math.min(a, Math.min(b, c)); } private static int calculateCost(char s, char t) { return s==t?0:1; } private static int[][] initializeMatrix(int s, int t) { int[][] matrix = new int[s + 1][t + 1]; for (int i = 0; i <= s; i++) { matrix[i][0] = i; } for (int j = 0; j <= t; j++) { matrix[0][j] = j; } return matrix; } public static int computeLevenshteinDistance(final String s, final String t) { char[] s_arr = s.toCharArray(); char[] t_arr = t.toCharArray(); if(s.equals(t)) { return 0; } if (s_arr.length == 0) { return t_arr.length;} if (t_arr.length == 0) { return s_arr.length;} int matrix[][] = initializeMatrix(s_arr.length, t_arr.length); for (int i = 0; i < s_arr.length; i++) { for (int j = 1; j <= t_arr.length; j++) { matrix[i+1][j] = minOfThree(matrix[i][j] + 1, matrix[i+1][j - 1] + 1, matrix[i][j - 1] + calculateCost(s_arr[i], t_arr[j-1])); } } return matrix[s_arr.length][t_arr.length]; } } |
Algorithm Visualization: http://www-igm.univ-mlv.fr/~lecroq/seqcomp/node2.html
Code: LevenshteinDistance.java
Setting Multicast Time To Live in Java
I know that this seems trivial, but there are a few gotchas that have burned me a few times so I thought I would post the solution here.
The API will lead you to write this
MulticastSocket socket = new MulticastSocket(6000);
socket.setTimeToLive(16);
And you’ll feel pretty good about it, but then you will deploy your software only to find out that the packets aren’t clearing the first router hop. Then you’ll fire up ethereal and upon inspection you will notice that the TTL in the packet is 0. What the hell? You can clearly see where you set it to 16.
There is a small hiccup inside java where they have been blending the java.net API to be stack agnostic and if you are on a dual stack (IPv4 & IPv6) capable machine and are only using the IPv4 stack you need to notify the JVM by setting a special system property. This can be done two ways:
First you can set the property in code
Properties props = System.getProperties();
props.setProperty("java.net.preferIPv4Stack","true");
System.setProperties(props);
I agree with you that the third line doesn’t look nessecary, but in my experiance it is. Or you can set this option from the command-line:
java -Djava.net.preferIPv4Stack=true -jar program.jar
I hope this post helps, because I was ready to tear my hair out.
Unit Testing: User Interfaces
One sticking point a lot of people seem to have is how to unit test a user interface. I’ve read many articles by TDD advocates saying that you absolutely need to have unit tests for your GUI components, and then I’ve also read articles from the RAD tool crowd who say that because of the method of genesis the cost of testing out weighs the benefit. While both groups are certain to remain dead-set against each other, I prefer to take a more pratical approach. I do tend to disagree with the TDD folks that all tests must be written first, as long as there is sufficiant coverage I don’t really care when the test gets written. I believe that it is one of the many jobs of a professional engineer to know when which approach is appropriate for the environment they are operating in. However I strongly disagree with the RAD folks who say that because their UI code was computer generated, it doesn’t need testing. Unit testing is about validating functional behavour, now RAD tools will layout widgets all day long, but they make no guarentee as to what happens when you click a button.
A hybrid approach
Now when looking a the visual appeal of a panel, there is no tool that is better than the human eye. Granted it sometimes does depend on the human, but there are not going to be any tools out there that can ‘test’ for style, continuity etc.. What you can test is the outcome of user interaction. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JList; import javax.swing.JPanel; public class ExamplePanel extends JPanel { private JButton clearButton = new JButton("Clear"); private DefaultListModel listModel = new DefaultListModel(); public ExamplePanel() { super(new BorderLayout()); listModel.addElement("test"); listModel.addElement("test2"); listModel.addElement("test3"); add(new JList(listModel), BorderLayout.CENTER); add(clearButton, BorderLayout.SOUTH); clearButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { listModel.clear(); } }); } } |
Now when you look at this class you will notice that the only testable function of the panel is the constructor. So you will probably start off with a testcase that looks like:
1 2 3 4 5 6 7 | public class ExamplePanelTest extends TestCase { public void testExamplePanel() { assertNotNull(new ExamplePanel()); } } |
And you would see in your coverage report that you have covered 87% of the panel, that’s great right? Well not really, all you’ve tested is that when you new this object an exception isn’t thrown and that really is insufficient for proving that your panel does what you’ve intended. Ideally we would like to know what happens when somebody clicks the “Clear” button.
I’ve attached to the bottom of this post a file that contains some convenience methods for iterating through the java UI containers to locate widgets of interest. Using this class allows us to write more comprehensive test cases. For example, this is how I would test the above class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public class ExamplePanelTest extends TestCase { public void testExamplePanel() { ExamplePanel panel = new ExamplePanel(); assertNotNull(panel); //This returns a list of all the JLists //that are contained within the panel List lists = UiTestUtils.findAllInstances(JList.class, panel); assertEquals(1, lists.size()); //We should only have one list //The list should have 3 elements assertEquals(3, lists.get(0).getModel().getSize()); JButton clearButton = UiTestUtils.findButtonByText("Clear", JButton.class, panel); assertNotNull(clearButton); //There should be a clear button in the panel clearButton.doClick(); //this is the method that simulates clicking the button //The list should have 0 elements assertEquals(0, lists.get(0).getModel().getSize()); } } |
Now you can see that I am using the iterative property of swing widgets to search through the children and locate the interesting widgets, and then I can simulate interaction with them. As you can see this test case will cover 100% of my GUI class, and it was extremely easy to do. Also my test does not rely on ‘volatile criteria’ such as widget placement to test the functionality. This allows me to make aesthetic changes to the class without breaking my unit tests. Happy Testing.
File Download: UITestUtils.java


