Verify that all getter methods are called - java

I have the following test where I need to verify that all getters of the Person class are being called. So far I have used mockito's verify() to make sure that each getter is called. Is there a way to do that by reflection? It can be the case that a new getter is added to the Person class but the test will miss that.
public class GetterTest {
class Person{
private String firstname;
private String lastname;
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
}
#Test
public void testAllGettersCalled() throws IntrospectionException{
Person personMock = mock(Person.class);
personMock.getFirstname();
personMock.getLastname();
for(PropertyDescriptor property : Introspector.getBeanInfo(Person.class).getPropertyDescriptors()) {
verify(personMock, atLeast(1)).getFirstname();
//**How to verify against any getter method and not just getFirstName()???**
}
}
}

Generally, don't mock the class under test. If your test is for a Person, you shouldn't ever see Mockito.mock(Person.class) in it, as that's a pretty clear sign that you're testing the mocking framework instead of the system-under-test.
Instead, you may want to create a spy(new Person()), which will create a real Person implementation using a real constructor and then copy its data to a Mockito-generated proxy. You can use MockingDetails.getInvocations() to reflectively check that every getter was called.
// This code is untested, but should get the point across. Edits welcome.
// 2016-01-20: Integrated feedback from Georgios Stathis. Thanks Georgios!
#Test
public void callAllGetters() throws Exception {
Person personSpy = spy(new Person());
personSpy.getFirstname();
personSpy.getLastname();
assertAllGettersCalled(personSpy, Person.class);
}
private static void assertAllGettersCalled(Object spy, Class<?> clazz) {
BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
Set<Method> setOfDescriptors = beanInfo.getPropertyDescriptors()
.stream()
.map(PropertyDescriptor::getReadMethod)
.filter(p -> !p.getName().contains("getClass"))
.collect(Collectors.toSet());
MockingDetails details = Mockito.mockingDetails(spy);
Set<Method> setOfTestedMethods = details.getInvocations()
.stream()
.map(InvocationOnMock::getMethod)
.collect(Collectors.toSet());
setOfDescriptors.removeAll(setOfTestedMethods);
// The only remaining descriptors are untested.
assertThat(setOfDescriptors).isEmpty();
}
There might be a way to call verify and invoke on the Mockito-generated spy, but that seems very fragile, and very dependent on Mockito internals.
As an aside, testing bean-style getters seems like an odd use of time/effort. In general focus on testing implementations that are likely to change or break.

I can think of two solutions for your problem:
Generate the Builder code programmatically, so you don't need to run tests. Java code is generated by a program and never edited by a user. Test the generator instead. Use a text template and build definitions from a serialized domain model or directly from Java compiled classes (you'll need a separate module dependent on the bean's one)
Write your tests against a proxy library. The problem is that regular proxies can only implement interfaces, not regular classes, and it's very cumbersome to have interfaces for Javabeans. If you choose this route, I'd go with Javassist. I coded a runnable sample and put it on GitHub. The test cases use a proxy factory to instantiate beans (instead of using new)
public class CountingCallsProxyFactory {
public <T> T proxy(Class<T> classToProxy) {
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;
}
public void verifyAllGettersCalled(Object bean) {
// Query the counter against the properties in the bean
}
}
The counter is kept inside the class MethodCallCounter

Related

How efficiently create Java proxy object using CGLib (or any other reflection/byte-code library)

Objective: (as the question title says): to efficiently create proxy (domain) objects using CGLib or any other reflection library (e.g. ByetBuddy?)
Having our domain class (please note Lombok annotations):
#Getter
#Setter
#RequiredArgsConstructor
public class DomainFoo {
#NonNull
private final Integer id;
// some other fields, final or otherwise!
public void doSomething() {
// do something here!
}
}
I'm trying to create a proxy object of type DomainFoo which responds only to getId method with the given ID (see below), otherwise (calling any other method) it throws an UnsupportedOperationException.
I managed to do this using GCLib (Spring version if it matters):
public static final ObjenesisStd OBJENESIS = new ObjenesisStd();
public static Factory newFoo(Integer id) {
val enhancer = new Enhancer();
enhancer.setSuperclass(domainClass);
enhancer.setCallbackType(MethodInterceptor.class);
val proxyClass = enhancer.createClass();
// Since there's no default constructor in domains:
val instantiator = OBJENESIS.getInstantiatorOf(proxyClass);
val proxyInstance = instantiator.newInstance();
val factory = (Factory) proxyInstance;
factory.setCallbacks(new Callback[]{new DomainProxyInterceptor(id)});
return factory; // see below for why it's called factory!
}
where DomainProxyInterceptor is:
#RequiredArgsConstructor
private class DomainProxyInterceptor implements MethodInterceptor {
#NonNull
private final Integer id;
#Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.getDeclaringClass() != Object.class && method.getName().equals("getId")) {
return id;
} else {
throw new NotSupportedException(method.getName());
}
}
}
Everything works just fine. Now to make it efficient, I'm trying to cache factory and actually use it a factory:
// newFooFactory is the above method rename!
private static final Factor FOO_FACTORY = newFooFactory(0);
public static DomainFoo newFoo(Integer id) {
val callbacks = new Callback[]{new DomainProxyInterceptor(id)};
return (DomainFoo) FOO_FACTORY.newInstance(callbacks);
}
But calling the above method throws a NoSuchMethodError:
Exception in thread "main" java.lang.NoSuchMethodError: com/example/demo/DomainFoo$$EnhancerByCGLIB$$8423c3c4.<init>()V (loaded from file:/Users/rad/works/demo/target/classes/ by jdk.internal.loader.ClassLoaders$AppClassLoader#85a856f6) called from class com.example.demo.DomainFoo$$EnhancerByCGLIB$$8423c3c4 (loaded from file:/Users/rad/works/demo/target/classes/ by jdk.internal.loader.ClassLoaders$AppClassLoader#85a856f6).
at com.example.demo.DomainFoo$$EnhancerByCGLIB$$8423c3c4.newInstance(<generated>)
at com.example.demo.DomainFactory.proxyFoo(DomainFactory.java:28)
at com.example.demo.DemoApplication.main(DemoApplication.java:6)
Which presumably is because Factory.newInstance tries to use the normal constructor but it's not there (because we created the object using Objenesis?).
I also tried ReflectionFactory to create the factory instance, but it has the same issue.
Questions (they're kinda related):
Do I need to worry about efficiency at all? (Those objects are normal domains, so there's usually too many of them.)
Is there a better way to do the above? In terms of efficiency or otherwise? Specifically what's the right way to instantiate using GCLib when there's no default constructor?
Is there a way to fix the above issue? Resolving NoSuchMethodError failure?
Any other library or solution I could try?
Thanks.
Cglib and ByteBuddy are 2 good libraries to create a proxy. Objenesis will do something more on top. It will prevent calling a constructor of the proxied class. You can look at org.easymock.internal.ClassProxyFactory or use it to create such a proxy. It is quite similar to your code.

Fluent Interface in Spring Boot Service

I am building a Spring Boot project for work.
In this project I have service which is tasked with getting certain Documents from another backend. There a quite a lot of different scenarios where the documents have to meet certain criteria e.g. be from a certain date, which can be matched freely. Currently this is accomplished with normal method like so:
#Service
public class DocumentService(){
private OtherService otherService;
#Autowire
public DocumentService(OtherService otherService){
this.otherService = otherService;
}
public List<Document> getDocuments() {
...
}
public List<Document> getDocuments(LocalDate date) {
...
}
public List<Document> getDocuments(String name){
...
}
public List<Document> getDocuments(String name, LocalDate date){
...
}
}
I find this to be a rather bad solution because for every new combination there would need to be a new method.
For that reason I'd like to use a fluent style interface for that, something like this:
//Some other class that uses DocumentService
documentService().getDocuments().withDate(LocalDate date).withName(String name).get();
I'm familiar with the Builder Pattern and method chaining but I don't see a way how I can adapt either one of those. Seeing as, per my understanding, #Service-classes are singletons in Spring Boot.
Is this at all possible with Spring Boot?
Doesn't have to be a Spring Boot solution, why not just introduce a POJO builder-like local class:
#Service
public class DocumentService(){
public Builder documents() {
return new Builder();
}
public class Builder {
private LocalDate date;
private String name;
public Builder withDate(LocalDate date) {
this.date = date;
return this;
}
// etc
public List<String> get() {
final List<SomeDTO> results = otherService.doQuery(name, date, ...);
// TODO - tranform DTO to List<String>
return list;
}
}
}
Obviously make it static if it doesn't need access to the parent component.
You could make the Spring component and the builder be the same object but that does feel contrived, also I expect you would like to be able to support multiple builders.
Also I'm assuming the parent component is genuinely a service, i.e. it doesn't contain any state or mutators, otherwise you are introducing potential synchronization problems.
EDIT: Just for illustration the builder maintains the arguments to be passed to the otherService and performs any service-like transforms.
If you want to use a fluent interface here, the object returned by your getDocuments() method would have to be the starting point for the method chain. Perhaps create something like a DocumentFilter class that you can return from there, then you'll end up with something like this:
documentService.documents().getDocuments().withDate(LocalDate date).withName(String name).getDocuments()
In this example, your DocumentFilter will have withDate(...) and withName(...) methods, and each subsequent call includes all of the criteria from the preceding DocumentFilter.

How to verify method call typsafe in junit with spring?

how can I replace the methodName("getEmployeeDetailsById") with a typesafe expression? Somehow linking directly to the method of the class. Is that possible?
#RunWith(SpringRunner.class)
#WebMvcTest
public class MyTest {
#Test
public void test() {
mockMvc
.perform(get("/employee/details/9816"))
.andExpect(handler().handlerType(EmployeeController.class))
.andExpect(handler().methodName("getEmployeeDetailsById")); //TODO typesafe?
}
If I don't misunderstand your intention, you want build the expectation in static way.
You can use spring HandlerResultMatchers#methodCall & MvcUriComponentsBuilder#on to achieve your way, for example:
mockMvc.perform(get("/employee/details/9816")).andExpect(
handler().methodCall(on(EmployeeController.class).getEmployeeDetailsById(args))
// args is any of the arbitrary value just to make the code to compile ---^
)
But one thing you need to note is that MvcUriComponentsBuilder#on will create a proxy to be able to inspect the previous invocations. when you make the handler method to return a String view name, you should make the return type of handler method with its super type (super interface or superclass) of the String class, since it is final and can't be proxied by cglib. for example:
#RequestMapping("/foo")
public Object handlerReturnViewName() {
// ^--- use the super type instead
return "bar";
}
You can find the method in your Controller which has a #GetMapping annotation (i'm assuming what annotation you use here, adjust as required) with the value of "/employee/details/{id}" by searching for it over all methods in the class:
private String findMethodName() {
List<Method> methods =
new ArrayList<>(Arrays.asList(EmployeeController.class.getMethods());
for (Method method : methods) {
if (method.isAnnotationPresent(GetMapping.class)) {
GetMapping annotation = method.getAnnotation(GetMapping.class);
if(Arrays.asList(annotation.value())
.contains("/employee/details/{id}") {
return method.getName();
}
}
}
}
Then you can call this method in your mvcTest:
.andExpect(handler().methodName(findMethodName()));

JAVA Is it possible to dynamically have a class extend another?

I've been at this since yesterday looking for a way to do this. What I have are hundreds of POJOs from a third party and need to apply properties to these based on business rules. I'm avoiding the altering of the POJOs because the third party could potentially recreate them thus creating a nightmare for managing files down the road.
What I'm attempting to do is to dynamically have a class extend another class.
For example.
POJO: Foo.java
package abc.service;
public class Foo {
private String greeting = "";
public Foo(){
gretting = "Good morning";
}
public String getGreeting(){
return greeting;
}
}
// end file
Mine: Bar.java
package abc.service;
public class Bar {
private String claim = "";
public Bar(){
claim = "You're correct";
}
public String getClaim(){
return claim;
}
}
// end file
Mine: TestMe.java
Trying here in a class separate from the POJOs to have a POJO extend another of my classes.
Is this beyond the abilities of JAVA?
package abc;
public class TestMe {
Foo f = new Foo();
Class c1 = f.getClass();
Bar b = new Bar();
Class c2 = b.getClass();
Class merged = c2.asSubclass(c1);
// Trying to call the Foo method
System.out.println(merged.getGreeting());
// Trying to call the Bar method
System.out.println(merged.getClaim());
}
Additionally what is going on is that JSON schemas are being created from the POJOs that are provided. But the POJOs are only based on an UPDATE record scenario. I'm looking for the best way to have the POJOs extend another class for CREATE record scenarios which is why I'm looking to dynamically have their POJOs extend my code when required.
Need to generate json schema for the POJOs for UPDATE
Need to verifying their json meets the POJOs requirements for UPDATE
Need to convert their json to the POJOs for UPDATE
Also,
Need to generate json schema for the POJOs for CREATE
Need to verifying their json meets the POJOs requirements for CREATE
Need to convert their json to the POJOs for CREATE
Using Jackson Mixin and the ObjectMapper I'm able to dynamically apply my code to the classes when creating the schemas but the issue I'm having is when trying to have the POJOs extend the class where Mixin is not going to solve the issue.
With plain Java: no, it can't be done.
You can change byte code, either in the build process, or at runtime. But it's hard, and there's not a lot of documentation.
AspectJ's declare parents expression is probably the easiest way to do it at build time.
If you want to do it at runtime, look at frameworks like asm, CGLib or ByteBuddy. But you will have to run the code from inside a custom ClassLoader or agent.
You can use composition instead of inheritance.
public class Foo {
private String greeting = "";
public Foo(){
gretting = "Good morning";
}
public String getGreeting(){
return greeting;
}
}
Your class
public class Bar {
private String claim = "";
private Foo foo;
public Bar(){
claim = "You're correct";
foo = new Foo();
}
public String getClaim(){
return claim;
}
public Foo getFoo(){
return foo;
}
}
And the test
public class TestMe {
// Trying to call the Foo method
System.out.println(bar.getFoo().getGreeting());
// Trying to call the Bar method
System.out.println(bar.getClaim());
}
Or you can do you class a little bit different.
public class Bar {
private String claim = "";
private Foo foo;
public Bar(){
claim = "You're correct";
foo = new Foo();
}
public String getClaim(){
return claim;
}
public String getGreeting(){
return foo.getGreeting();
}
}
And the test
public class TestMe {
// Trying to call the Foo method
System.out.println(bar.getGreeting());
// Trying to call the Bar method
System.out.println(bar.getClaim());
}
It is Not Possible.
Simply to put, JAVA at present(till latest version) does not have a provision to dynamically extend the class at runtime and load to JVM.
Instead of extending, you should use a design pattern. For example the Stategy Pattern. This allows you to change your strategy dynamicaly.

Exception trying to change a CGLib proxy field value

I created a CGLib dynamic proxy of a class, but when I try to access any field declared in the original class, I obtain java.lang.NoSuchFieldException. I need to obtain the field in order to change its value.
By the way, this is the class the proxy is based on:
public class Person {
private String name;
....
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
...
}
And this is the code snippet (inside the "intercept" method of the "MethodInterceptor") that is raising the mentioned exception (more specifically the first line):
public Object intercept(Object instance, Method jdkMethod, Object[] args, MethodProxy method) throws Throwable {
...
Field field = instance.getClass().getField("name");
field.setAccessible(true);
field.set(instance, "foo");
....
Do you know any other way to access the needed field or change its value?
Thanks.
Apparently, a CGLib proxy is a subclass of the original class. So, the following code worked well:
Field field = instance.getClass().getSuperclass().getDeclaredField("name");
Try:
Field field = instance.getClass().getDeclaredField("name");
As mentioned in this SO answer, getField only works for public fields, but applies to the entire class hierarchy. You can think of it as inspecting the public interface of the class. getDeclaredField works for private fields, and will not inspect the class hierarchy; you can think of it as resolving the implementation of the class.
Even though you already figured out how to fix your problem, here is a short explanation of how cglib works and what is causing you problems. Considering your Person class, cglib creates another class at runtime which is representing your proxy. This class would approximately look like the following in Java source code, however, many of the instances used are cached which is why cglib adds several other fields. Furthermore, the MethodInterceptor is injected by using different static fields:
public class Person$EnhancedByCglib extends Person {
private static class GetNameMethodProxy extends MethodProxy {
#Override
public Object invokeSuper(Object instance,
Object[] arguments) {
return ((Person$EnhancedByCglib) instance).getNameSuper();
}
// ...
}
// ...
private static MethodInterceptor methodInterceptor;
#Override
public String getName() {
return (String) methodInterceptor.intercept(this,
getClass().getDeclaredMethod("getName"),
new Object[0],
new GetNameMethodProxy());
}
private String getNameSuper() {
return super.getName();
}
#Override
public void setName(String name) {
methodInterceptor.intercept(this,
getClass().getDeclaredMethod("setName", String.class),
new Object[] {name},
new SetNameMethodProxy());
}
private void setNameSuper(String name) {
super.setName(name);
}
// ...
}
As you can see, the interception is implemented by overriding any method. This way, your MethodInterceptor is invoked instead of the original method which is still invokable by using the MethodProxy. Due to the interception, calling getMethod or getDeclaredMethod works as expected when using cglib. Fields are however not inherited which is why you need to browse the class hierarchy one class up. This is why:
instance.getClass().getSuperclass().getDeclaredField("name");
works. Note that cglib is not longer maintained. Have a look at my library Byte Buddy in case that you are looking for an alternative. Note however that I am releasing a fully stable version sometime next week. The current v0.1 release contains some premature features.

Categories