VIP: The Right
Way to do the Wrong Thing
Introduction
How Does It Work?
Fake Accessors
Example
Download
Contact
Introduction
If you write unit tests in your java projects, then you had this
problem before: testing private members. There are four solutions for
testing private methods:
- Don't test private methods: Don't do
that. Really.
- Give the methods package access:
Simple but intrusive, because you're changing your code just for the
sake of testing.
- Use a nested test class: Even
more intrusive, because testing code will be deployed with production
code.
- Use reflection: non-intrusive but
non-elegant code.
I wrote VIP because I prefer using reflection in
my test cases, but I
don't like all that reflection code hanging around. So I came with a
very small and simple utility that will do the reflection rubbish for
you.
VIP stands for Very Important Proxy ;-)
How
Does It Work?
VIP creates a dynamic proxy that implements an interface defined by
you. No xml configuration needed; the interface should have all info
needed by VIP. If you want to test a private method, then add the same
method signature to the interface (except for modifiers like private, static,
etc). VIP returns you a dynamic proxy that implements
that interface, so you may invoke the method as if it was public. VIP
holds an instance of the target class (class under test) and forwards
the method invocation, matching the method signatures and doing all the
reflection rubbish for you.
Fake
Accessors
Beside invoking private methods, you may also checkout private fields.
If the target class does not provide public accessors, VIP offers you
fake accessors. All you have to do is to declare the accessors in your
custom interface, following java naming conventions. When you invoke a
fake accessor VIP figures out that there is no matching method in the
target class and tries to find a matching field for the accessor name.
Example
Suppose you want to test the following target class:
public class Foo {
private int unreachable = 10;
private String sayBar() {
return "Bar!";
}
public Foo() {
}
}
Step
1: Define a custom interface, declaring as public all the
private
members you want to access. This should go together with all the
testing code that will not be deployed with your application. I advise
to include it in the same file of your test case.
interface IFoo {
int getUnreachable();
void setUnreachable(int unreachable);
String sayBar();
}
Step
2: Ask VIP for a proxy in your unit test.
public void testFoo() throws Exception {
...
IFoo proxy = (IFoo) VIPMaker.makeProxyForInstance(new Foo(), IFoo.class);
proxy.setUnreachable(20);
assertEquals(20, proxy.getUnreachable());
assertEquals("Bar!", proxy.sayBar());
...
}
That's
all. You may also call VIPMaker.makeProxyForClass(Class, Class), in
case you want VIP to instantiate the target class for
you, trying all possible constructors.
Contact
Bernardo O. Bennett is a java consultant, currently working with Sakonnet Technology LLC.
If you have questions or suggestions send me an e-mail.