1

I write up a simple function below to illustrate what I try to achieve.

public class MyTempClass {
    private boolean myVariable = false;

    private void setupMyVariable() {
        // Some callback etc from a web service that will determine the myVariable value
        myVariable = true;
    }

    public void doSomethingIfVaraibleIsTrue() {
        if (myVariable) {
            // Do something.
        }
    }
}

I would want to unit test MyTempClass doSomethingIfVaraibleIsTrue function is doing something when myVariable is true, and not doing something when myVariable is false. However myVariable is a private boolean, and not easily set (e.g. it is set from a callback of a service).

I also don't want to make a setter for myVariable as it is really private to the class. Is there any way to Mock/Stud or make myVariable true so that I could unit test my doSomethingIfVaraibleIsTrue?

Elye
  • 53,639
  • 54
  • 212
  • 474
  • Are you able to mock the callback such that the variable will naturally be set to `true`? – JonK Jun 08 '16 at 08:46
  • That was what I'm intending to do, and would be most elegant. But it is also something internal and not injected... so can't mock. Perhaps the design need to be improved. – Elye Jun 09 '16 at 00:23

2 Answers2

3

As per my opinion, just for testing purpose you must not change visibility of any field or method. This is wrong practice and It breaks the encapsulation.

Instead you can define one generic method in some Util class and then you can change the values of private variables through reflection. You can define some kind of Util class, say TestUtils and inside it you can have below method:

class TestUtils {

    public static void setPrivateField(Object targetObject, String fieldName,
          Object valueToSetOnThisField) {

          try {
             Field f = obj.getClass().getDeclaredField(fieldName);
             f.setAccessible(true);
             f.set(obj, valueToSet);
          } catch (Exception e) {
            // Handle the exception accordingly
          }
       }
}

Now you can use this class in your test class as below:

MyTempClass targetObj = new MyTempClass();

// Change private variable "myVariable" to true
TestUtils.setPrivateField(targetObj, "myVariable", Boolean.TRUE);
Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
pbajpai
  • 1,303
  • 1
  • 9
  • 24
  • Given my situation, though I don't like reflection, perhaps this' the most convenient approach. – Elye Jun 09 '16 at 00:26
1

Make it package visible then it can be read and set by the test class but not by other classes ie remove the private keyword but don't put public. IE

public class MyTempClass {
    boolean myVariable = false;

    private void setupMyVariable() {
        // Some callback etc from a web service that will determine the myVariable value
        myVariable = true;
    }

    public void doSomethingIfVaraibleIsTrue() {
        if (myVariable) {
            // Do something.
        }
    }
}
Arthur
  • 3,376
  • 11
  • 43
  • 70
  • I don't think that breaking encapsulation for purposes of unit tests only is good solution. – John Jun 08 '16 at 08:56
  • the package is still encapsulated, it's not public only classes in the same package will be able to change it. otherwise break the class and test into smaller chunks. ie make a getter and setter , and test it, if you want a object that does not have the getters and setters write a wrapper class. – Arthur Jun 08 '16 at 09:28
  • 2
    as an afterthought if you cant test the behavior of the class in back box fashion i think your class is trying to do to much or your test is not a good test. – Arthur Jun 08 '16 at 09:30