Skip to content

Instantly share code, notes, and snippets.

@RaffaeleSgarro
Created January 13, 2016 22:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RaffaeleSgarro/84740ae6a0d16d037439 to your computer and use it in GitHub Desktop.
Save RaffaeleSgarro/84740ae6a0d16d037439 to your computer and use it in GitHub Desktop.
Test library to assert that all getters of a bean are called using Javassist proxies

Self contained Java sample

Requirements

  • TestNG 6.8
  • Javassist 3.20
package com.stackoverflow;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.beans.*;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import static org.testng.Assert.fail;
public class EnsureAllFieldsAreRead {
/**
* This is a standard JavaBean domain class
*/
public static class Person {
public String name;
public int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
/**
* API class
*
* Objects proxied by this factory keep counters of method invocations
*/
public static class CountingProxyFactory {
@SuppressWarnings("unchecked")
public <T> T proxy(Class<T> classToProxy) {
try {
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(classToProxy);
Class clazz = factory.createClass();
T instance = (T) clazz.newInstance();
ProxyObject proxy = (ProxyObject) instance;
MethodCallCounter handler = new MethodCallCounter();
proxy.setHandler(handler);
return instance;
} catch (Exception e) {
throw new RuntimeException("Could not proxy class", e);
}
}
public void verifyAllGettersCalled(Object bean) {
if (!(bean instanceof ProxyObject)) {
fail("This bean is not a proxy!");
}
ProxyObject proxy = (ProxyObject) bean;
if (!(proxy.getHandler() instanceof MethodCallCounter)) {
fail("Could not find handler for " + bean + ". This object were not made by this factory!");
}
MethodCallCounter handler = (MethodCallCounter) proxy.getHandler();
handler.countAccessOfGetters(bean.getClass());
}
}
/**
* This is simply a counter
*/
private static class MethodCallCounter implements MethodHandler {
private final Set<String> counter = new HashSet<>();
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
counter.add(thisMethod.getName());
Class<?> returnType = thisMethod.getReturnType();
if (returnType.isPrimitive()) {
if (returnType.equals(int.class)) {
return 0;
} else if (returnType.equals(double.class)) {
return 0.0;
} else if (returnType.equals(boolean.class)) {
return false;
} else if (returnType.equals(char.class)) {
return 0;
} else {
throw new RuntimeException("I forgot to program return value for " + returnType.getName());
}
} else {
return null;
}
}
public void countAccessOfGetters(Class<?> beanProxyClass) {
Class<?> beanClass = beanProxyClass.getSuperclass();
BeanInfo info;
try {
info = Introspector.getBeanInfo(beanClass, Object.class);
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
PropertyDescriptor[] pds = info.getPropertyDescriptors();
for (PropertyDescriptor prop : pds) {
String methodName = prop.getReadMethod().getName();
if (!counter.contains(methodName)) {
fail("Nobody called " + beanClass.getName() + "." + methodName + "()");
}
}
}
}
public static class TestCase {
private CountingProxyFactory countingProxyFactory;
private Person person;
@BeforeMethod
public void setUp() {
countingProxyFactory = new CountingProxyFactory();
person = countingProxyFactory.proxy(Person.class);
}
@Test
public void succeedBecauseAllMethodsAreCalled() {
person.getName();
person.getAge();
verifyGettersCalls();
}
@Test
public void failBecauseSomeMethodsAreNotCalled() {
person.getName();
verifyGettersCalls();
}
private void verifyGettersCalls() {
countingProxyFactory.verifyAllGettersCalled(person);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment