Unit testing MBeanServer interactions
Does anyone have any recommendations for unit testing JMX classes? Say for example you want to test some method you wrote that has to query an MBeanServer and return some ObjectNames (I realize this is an over-simplification, but maybe suitable for discussion purposes). What's a good way to do something like that without having to implement a whole MockMBeanServer, and so on. Or is that the only way? Are there any test patterns or anything like that anyone has developed? Thanks for any ideas.
[505 byte] By [
aakturea] at [2007-11-26 16:20:39]

# 1
Hi,
Don't implement a mock MBeanServer - simply create an MBeanServer and use it.
Let's assume I want to test a method I have written, which should return me all
domains containing an instance of ThingMBean. Now let's assume that I know
that all instance of ThingMBean have an ObjectName which contains the key
'type=Thing' - and that no other MBean will have such a key.
This would be the implementation of my method:
public class Utils {
public static String[] getDomainsOfThing(MBeanServer server)
throws JMImplementation {
final ObjectName pattern = new ObjectName("*:type=Thing,*");
final Set<String> domains = new HashSet<String>();
for (ObjectName name : server.queryNames(pattern,null)) {
domains.add(name.getDomain());
}
return domains.toArray(new String[domains.size()]);
}
}
Then I would simply write my unit test as this:
public class UtilsTest {
public interface TestMBean { }
public static class Test implements TestMBean {}
private static String[] matchingnames {
"domain1:type=Thing,foo=bar",
"domain1:type=Thing",
"domain2:type=Thing",
"domain3:type=Thing,foo=bar",
};
private static String[] notmatchingnames {
"domain3:type=ThingX,foo=bar",
"domain4:type=AThing,foo=bar",
"domain5:type=ThingThing",
"domain6:type=thing,foo=bar",
"domain7:type= Thing",
"domain8: type=Thing",
};
private static void createTestMBeans(String[] names, MBeanServer server)
throws JMException {
for (String namestr : names) {
final ObjectName aname = new ObjectName(namestr);
server.registerMBean(new Test(),aname);
}
}
public static void testGetDomainsOfThing() {
final MBeanServer server = MBeanServerFactory.newMBeanServer();
// Fill the MBeanServer with dummy MBean which will match
createTestMBeans(matchingnames,server);
// Fill the MBeanServer with dummy MBean which will not match
createTestMBeans(notmatchingnames,server);
// compute expected result
final Set<String> expectedResult = new HashSet<String>();
for (String namestr : matchingnames) {
expectedResult.add(new ObjectName(namestr).getDomain());
}
// call my method
final String[] testResult = Utils.getDomainsOfThing(server);
// check that result is equal to expected result.
final Set<String> resultSet = new HashSet<String>();
resultSet.addAll(Arrays.asList(testResult));
if (!resultSet.equals(expectedResult))
throw new RuntimeException("test failed");
}
}
-- daniel
JMX, SNMP, Java, etc...
http://blogs.sun.com/jmxetc
# 3
Hi,
I don't see why this would be a problem - unless you run your tests inside a deployed
Application Server - in which case you'd better make sure that they aren't going
to be too intrusive ;-\
I must say that I haven't much experience in testing Java EE applications though.
For what it's worth, many of the JMX unit tests (the unit tests that test the JMX
implementation in the JDK) are crossing the border with what you would usually
call a unit test: The JMX technology defines a connector, and thus many of our
unit tests have to 'fake' a client/server set-up by running a server thread and a
client thread, just to ensure that everything still works when it goes through a
connector.
Of course it sometimes makes the analysis much more difficult when a test
actually fails - but as long as you write tests that really test what they are supposed
to test, you can't really go wrong. Sometimes however you discover to your
dismay that the bug was in fact in the test itself - which might have made false
assumptions...
Automating unit tests to run regularly (e.g. every night), and in particular after
any modification of the code base, is certainly a good practice in any case.
If you work within a team you might also pay attention to using a framework
that makes it easy for all the members of the team to understand how to run
the tests and how to get/interpret the results, and how to extend the test base.
If it's easy to do it will encourage everybody to write additional unit tests and
run them frequently. If it's overtly complex it will discourage everybody to
write tests - and you don't want that.
Well, that was my 2c ;-)
-- daniel
JMX, SNMP, Java, etc...
http://blogs.sun.com/jmxetc