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

dfuchsa at 2007-7-8 22:44:16 > top of Java-index,Core,Monitoring & Management...
# 2

Thanks Daniel, that was a big help. Another question. Have you ever run tests within the app server? As I was working on this, I also wrote a junit test suite that gets called by a startup class in weblogic, and runs some tests interacting with the weblogic mbean server. I know this kind of defeats the "fast and easy" rules for unit tests, but seemed appropriate for my needs. And the tests are run regularly via cruise control, so I know quickly if something breaks. Is this usually not recommended?

Alper

aakturea at 2007-7-8 22:44:16 > top of Java-index,Core,Monitoring & Management...
# 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

dfuchsa at 2007-7-8 22:44:16 > top of Java-index,Core,Monitoring & Management...
# 4
Thanks again, yes, someone could probalby write a book on unit/integrataion testing for jmx. Nice guitar on your blog, is that a Fender? I've been wanting a resonator for a long, long, long time.
aakturea at 2007-7-8 22:44:16 > top of Java-index,Core,Monitoring & Management...
# 5
Yes, it's a fender. But I'll tell you a secret: though I wish I could, I can't play it with a slide. I only know how to play chords :-(-- daniel
dfuchsa at 2007-7-8 22:44:16 > top of Java-index,Core,Monitoring & Management...