I have data model classes that contain private fields which are meant to be read-only (via a getter function). These fields are set by my JPA persistence provider (eclipselink) during normal operation, using the contents of the database. For unit tests, I want to set them to fake values from a mockup of the persistence layer. How can I do that? How does eclipselink set these values, anyway?
Simplified example:
#Entity
class MyEntity
{
#Id
private Integer _ix;
public Integer ixGet()
{
return this._ix;
}
}
Can you just Mock the Entity itself, providing your own implemenations of the getters?
You could create an anonymous extension in your mock persistence layer:
MyEntity x = new MyEntity() {
public Integer ixGet() { return new Integer(88); }
};
You need to use the Reflection API. Use Class.getField() to get the field, then call setAccessable(true) on that field so that you may write to it, even though it is private, and finally you may call set() on it to write a new value.
For example:
public class A {
private int i;
}
You want to set the field 'i' to 3, even though it is private:
void forceSetInt(Object o, String fieldName, int value) {
Class<?> clazz = o.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(o, value);
}
There are a number of exceptions that you will need to handle.
You can use a test library like Mockito to access objects internal state in read and write mode. For example with Mockito use:
//read
Integer i = Whitebox.getInternalState(myEntity,"_ix")
//Write
Whitebox.setInternalState(myEntity,"_ix", 123)
You can use a mocking framework like powermock to by pass encapsulation. In powermock you'd use Whitebox.setInternalState(..) to set a private member.
A less invasive method would be to mock the getter method. Whether this is feasible would depend on what else depends on the internal state but if it is enough, it's the cleaner solution.
Some methods I've used in the past:
Make _ix protected, create a subclass where you implement a setter
Make a constructor taking the value for _ix as a parameter
Use reflection
Another option, if you really hate to make things public, is to create a subclass for testing, and provide public access there.
You have a few options:
Create stubs to replace your entity (extract an interface first)
Use Reflection
Add a public setter for testing
Keep your tests within the package and use a default scope
For a bunch of useful techniques, have a look at Michael Feather's book, Working Effectively With Legacy Code
You can add constructor with parameter for your read-only variable. Don't forget to add a default (zero parameter) constructor.
#Entity
class MyEntity
{
#Id
private Integer _ix;
public MyEntity(Integer ix) {
_ix = ix;
}
public MyEntity() {
/*
* Default constructor
*/
}
public Integer ixGet()
{
return this._ix;
}
}
The constructor is a best way I think. If this entity has to be really readonly (not allowed to create new instances in production code at all) you can make constructor with package access and use it only within the tests. And there is a possibility that even if you make your default constructor private or with package access, your persistance provider still be able to work with such entity, but not sure though - check with eclipselink docs.
Related
I want to add unit tests for a method in class ClassToBeTested.execute(). ClassToBeTested is a business model class received from REST api. To call that method I have to:
create a class AAAclass (which must have 2 inner class mocked and stub 7 methods to put call the method I want to test)
put that mocked AAAclass in ClassToBeTested; ClassToBeTested depends on AAAclass
The AAAclass looks like:
public class AAAclass {
#SerializedName("BBBclass")
private BBBclass BBBclass;
public class BBBclass {
#SerializedName("CCCclass")
private CCCclass ccc;
public DDDclass getDDD() {
if (ccc != null) {
return ccc.getDDD();
}
return null;
}
}
private class CCCclass {
#SerializedName("DDDclass")
private DDDclass ddd;
public DDDclass getDDD() {
return ddd;
}
}
public class DDDclass {
}
}
I got the feeling that I'm doing sth wrong and it seems to be over mocking:
Don’t mock your model: Easier to read and you will may be add convenient constructor/factory methods to your production or test codebase.
So should I really add a special constructor just to use it in unit testing?
As was already mentioned it is hard to identify what are the objects and what is the context.
But it looks like the classes you'd mentioned are some DTOs but at the same time they have some business logic in their getters.
So first of all I would recommend you to extract the business logic to some other place (for instance some service). It should not be present in dto object.
Second. Why BBBclass, CCCclass and DDDclass are inner classes of AAAclass? Can't you make them static? Or event more can you extract them into separate classes? It is very important to decrease system complexity.
I think if you solve this issues you'll not need to mock such a complex object anymore.
At the same time remember if you're thinking of adding a constructor/method just for testability it is already a bad sign. It means that your system is becoming complex and abstractions don't work well. Try to rethink your abstractions.
So I am writing a class which I want to follow the best practices and be testable.
I have a new object to be created inside it. So, I am following the factory pattern to achieve it.
public class Apple {
// factory object injected in class
private SeedFactory seedFactory;
// Method to be tested
public void myMethod(String property1, int property2, String depends) {
// Just to set the necessary parameter
seedFactory = new SeedFactory(property1, property2);
// Factory pattern intact. Instance generation depends on only one parameter
SeedFactory result = seedFactory.getInstance(depends);
}
}
EDIT: Adding code for factory as well.
public class SeedFactory{
String property1;
int property2;
SeedFactory(property1,property2){
this.property1 = property1;
this.property2 = property2;
}
SeedFactory getInstance(int depends){
if(depends == 1)
{ // do stuff }
else{ // do stuff and return instance }
Now, before I actually create the new object, I have to make sure that I set two properties for the new instance to be generated, which are needed to be present irrespective of the type of instance generated by the factory. depends is the actual parameter which tells the factory what instance to return.
Now, as far as testability of this code is concerned, I can user PowerMockito to mock the factory object using whenNew but using PowerMockito is not a choice. I have to make it testable without it.
Also, I have tried to encapsulate the new call within a one line function and then use spy. But I want to avoid using spy, since it is not considered a good practice, in context of where this code is being used as a whole.
So my question is, Is there any way, without using PowerMockito, to re-write this class so that it can be unit tested properly?
If the instance to be generated needed only one parameter, then it would have been trivial. However, I don't want to pass more than one parameter to getInstance().
SeedFactory is not Apple's dependancy but your method depends on SeedFactory which has "uses" relationship. So to define proper relation i would suggest you use "USES" relation as below:
public void myMethod(SeedFactory seedFactory, String depends){ // Method to be tested
Now you could mock SeedFactory and can unit test it appropriately.
I think you're doing something wrong.
If SeedFactory isn't an Apple's dependency but an internal concern, hence you don't need to mock a SeedFactory to test Apple. You should test the public API provided by Apple only.
If SeedFactory is an Apple's dependency, so it definitely should be injected.
Is Javascript-like prototyping anyhow achievable, even using Reflection? Can I wrap my object inside another one, just to extend its functionality with one or two more methods, without wiring all its original nonprivate methods to the wrapper class, or extends is all I get?
If you are looking for extension methods, you could try Xtend. Xtend is language that compiles to java code and eliminates boilerplate code.
The following text is stolen from the Xtend Docs for extensions:
By adding the extension keyword to a field, a local variable or a parameter declaration, its instance methods become extension methods.
Imagine you want to have some layer specific functionality on a class Person. Let us say you are in a servlet-like class and want to persist a Person using some persistence mechanism. Let us assume Person implements a common interface Entity. You could have the following interface
interface EntityPersistence {
public save(Entity e);
public update(Entity e);
public delete(Entity e);
}
And if you have obtained an instance of that type (through a factory or dependency injection or what ever) like this:
class MyServlet {
extension EntityPersistence ep = Factory.get(typeof(EntityPersistence))
...
}
You are able to save, update and delete any entity like this:
val Person person = ...
person.save // calls ep.save(person)
person.name = 'Horst'
person.update // calls ep.update(person)
person.delete // calls ep.delete(person)
I don't think you can do this in Java. You can though in Groovy, using metaclasses
String.metaClass.world = {
return delegate + " world!"
}
println "Hello".world()
I want to provide annotations with some values generated by some methods.
I tried this so far:
public #interface MyInterface {
String aString();
}
#MyInterface(aString = MyClass.GENERIC_GENERATED_NAME)
public class MyClass {
static final String GENERIC_GENERATED_NAME = MyClass.generateName(MyClass.class);
public static final String generateName(final Class<?> c) {
return c.getClass().getName();
}
}
Thought GENERIC_GENERATED_NAME is static final, it complains that
The value for annotation attribute MyInterface.aString must be a constant expression
So how to achieve this ?
There is no way to dynamically generate a string used in an annotation. The compiler evaluates annotation metadata for RetentionPolicy.RUNTIME annotations at compile time, but GENERIC_GENERATED_NAME isn't known until runtime. And you can't use generated values for annotations that are RetentionPolicy.SOURCE because they are discarded after compile time, so those generated values would never be known.
The solution is to use an annotated method instead. Call that method (with reflection) to get the dynamic value.
From the user's perspective we'd have:
#MyInterface
public class MyClass {
#MyName
public String generateName() {
return MyClass.class.getName();
}
}
The annotation itself would be defined as
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface #MyName {
}
Implementing the lookup for both of these annotations is rather straight-forward.
// as looked up by #MyInterface
Class<?> clazz;
Method[] methods = clazz.getDeclaredMethods();
if (methods.length != 1) {
// error
}
Method method = methods[0];
if (!method.isAnnotationPresent(MyName.class)) {
// error as well
}
// This works if the class has a public empty constructor
// (otherwise, get constructor & use setAccessible(true))
Object instance = clazz.newInstance();
// the dynamic value is here:
String name = (String) method.invoke(instance);
There is no way to modify the properties of an annotation dynamically like others said. Still if you want to achieve that, there are two ways to do this.
Assign an expression to the property in the annotation and process that expression whenever you retrieve the annotation. In your case your annotation can be
#MyInterface(aString = "objectA.doSomething(args1, args2)")
When you read that, you can process the string and make the method invocation and retrieve the value. Spring does that by SPEL (Spring expression language). This is resource intensive and the cpu cycles are wasted every time we want to process the expression. If you are using spring, you can hook in a beanPostProcessor and process the expression once and store the result somewhere. (Either a global properties object or in a map which can be retrieved anywhere).
This is a hacky way of doing what we want. Java stores a private variable which maintains a map of annotations on the class/field/method. You can use reflection and get hold of that map. So while processing the annotation for the first time, we resolve the expression and find the actual value. Then we create an annotation object of the required type. We can put the newly created annotation with the actual value (which is constant) on the property of the annotation and override the actual annotation in the retrieved map.
The way jdk stores the annotation map is java version dependent and is not reliable since it is not exposed for use (it is private).
You can find a reference implementation here.
https://rationaleemotions.wordpress.com/2016/05/27/changing-annotation-values-at-runtime/
P.S: I haven't tried and tested the second method.
I want to extract private field values that are not marked by certain custom annotation, is this possible via BeanUtils? If yes, how?
Yes, assuming that you know the fields names. You can use PropertyUtils.getSimpleProperty(...). See also here for an example.
No, it is not possible with BeanUtils. But you can use Java's own reflection tools like this:
public class BeanUtilTest {
public static void main(String[] args) throws ... {
MyBean bean = new MyBean();
Field field = bean.getClass().getDeclaredField("bar");
field.setAccessible(true);
System.out.println(field.get(bean));
}
public static class MyBean {
private final String bar = "foo";
}
}
Please consider: Accessing private fields with reflection is very bad style and should be done only for tests or if you are sure there is no other way. If you don't have the ability to change the sources of the class you're trying to access, it might be a last resort. But consider that the behavior might change in the future (e.g. as an update of the library you're using) and break your code.
Edit: If BeanUtils or PropertyUtils are working, this means there is a public getter for this property and you should be using it instead of using reflection. Using PropertyUtils on a private field without a public getter throws a NoSuchMethodException.