Wednesday, January 26, 2005

Accessing Private Fields

I had read an article about unit testing private methods. As the article states, there are several approaches to this and also several reasons why you should consider NOT doing it (such as considering your design more carefully and testing public methods will indirectly test private ones). And while I'm still thinking about the merits of when you really need to test private methods, one thing did stand out to me and has proven very useful for my Monopoly Simulator.

I found that my Player objects should not expose their amount of cash as a publicly accessible field or method. Players in the real game of Monopoly, need not reveal how much money they have on hand. However, this presented a problem from two standpoints:
  1. The Bank (or some other aspect of the game) might need to know how much money they have left in order to properly control the flow of the game - I have yet to actually run into this scenario yet, so I'm going to employ the principle of YouArentGonnaNeedIt - and not worry about it until I need to.
  2. During unit testing, the cash level of a player indicates a successful test or not. This I have ran into and have used reflection to solve the problem.

Here is a method that accesses a private int field of any object:

private int getObjectPrivateIntValue(Class clazz, String fieldName, Object object) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
   Field field = clazz.getDeclaredField(fieldName);
   field.setAccessible(true);
   return field.getInt(object);
}

This is my first time bypassing the security of a class like this, so I'm not sure of all the ramifications yet. One thing I've noticed though, is that I'm tempted to put this kind of method into my actual application. This seems like a really bad idea. But, for unit testing code, it seems ok.

My next challenge, which is along these lines, is going to figure out how to make it so certain methods on Players (such as sendToJail() and pay(int amount) ) are only accessible to authorized classes (such as the Bank or Board objects). I can't make these methods package protected because other Player objects should not be allowed to call these methods. I need either some sort of SecurityManager. Maybe this is another place that aspects could help?


No comments: