42

I want to set the value of a private field using reflection for unit testing.

Problem is, that field is static.

Here's what I'm working from:

/**
   * Use to set the value of a field you don't have access to, using reflection, for unit testing.
   * 
   * Returns true/false for success/failure.
   * 
   * @param p_instance an object to set a private field on
   * @param p_fieldName the name of the field to set
   * @param p_fieldValue the value to set the field to
   * @return true/false for success/failure
   */
  public static boolean setPrivateField(final Object p_instance, final String p_fieldName, final Object p_fieldValue) {
    if (null == p_instance)
      throw new NullPointerException("p_instance can't be null!");
    if (null == p_fieldName)
      throw new NullPointerException("p_fieldName can't be null!");

    boolean result = true;

    Class<?> klass = p_instance.getClass();

    Field field = null;
    try {
      field = klass.getDeclaredField(p_fieldName);

      field.setAccessible(true);
      field.set(p_instance, p_fieldValue);

    } catch (SecurityException e) {
      result = false;
    } catch (NoSuchFieldException e) {
      result = false;
    } catch (IllegalArgumentException e) {
      result = false;
    } catch (IllegalAccessException e) {
      result = false;
    }

    return result;
  }

I realize this has probably already been answered on SO, but my search didn't turn it up...

Tom Tresansky
  • 19,364
  • 17
  • 93
  • 129
  • 3
    The obvious answer is "Jasus, don't mutate statics or privates of other classes." You could try Parameterisation from Above. – Tom Hawtin - tackline Jul 13 '10 at 16:09
  • if you are using spring you could set @Autowired on a private field, then if you need to replace that instance with a mock you need to change that using reflection from the test method – Jaime Hablutzel Jul 04 '11 at 18:19

2 Answers2

45

Basically the problem is your utility method, which assumes you have an instance. It's reasonably easy to set a private static field - it's exactly the same procedure as for an instance field, except you specify null as the instance. Unfortunately your utility method uses the instance to get the class, and requires it to be non-null...

I'd echo Tom's caveat: don't do that. If this is a class you have under your control, I'd create a package level method:

void setFooForTesting(Bar newValue)
{
    foo = newValue;
}

However, here's a complete sample if you really, really want to set it with reflection:

import java.lang.reflect.*;

class FieldContainer
{
    private static String woot;

    public static void showWoot()
    {
        System.out.println(woot);
    }
}

public class Test
{
    // Declared to throw Exception just for the sake of brevity here
    public static void main(String[] args) throws Exception
    {
        Field field = FieldContainer.class.getDeclaredField("woot");
        field.setAccessible(true);
        field.set(null, "New value");
        FieldContainer.showWoot();
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 9
    I think unit testing shouldn't push us to do anything in production classes as you state with: I'd create a package level method – Jaime Hablutzel Jul 04 '11 at 17:42
6

Just pass null for the object-instance argument. So:

field.set(null, p_fieldValue);

This will let you set the static field.

Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295