Self contained Java sample
- 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); | |
| } | |
| } | |
| } |