How to test private member objects without making a new object

Alex :

I'm trying to write unit test against a class. I can't change the class, but I think it's possible to test using reflection. I just don't know how to do it. Here's the class:

public class MyClass extends AnotherClass implements TheInterface
{
    private enum SomeTypes
    {
        SAMPLE01, SAMPLE02, SAMPLE03
    }

    private CircularList<SomeTypes> someTypesList; 
    Date date= new Date();
    private SomeOtherClassProcessor01 someOtherClassProcessor01;
    private SomeOtherClassProcessor02 someOtherClassProcessor02;
    private SomeOtherClassProcessor03 someOtherClassProcessor03;

    public Properties initialize (Properties properties) throws Exception
    {
        Properties propertiesToReturn = super.initialize(properties);
        someTypesList = new CircularList<SomeTypes>    (Arrays.asList(SomeTypes.values())); 
        someOtherClassProcessor01 = new SomeOtherClassProcessor01(); 
        someOtherClassProcessor02 = new SomeOtherClassProcessor02(); 
        someOtherClassProcessor03 = new SomeOtherClassProcessor03(); 

        return propertiesToReturn;
    }

    @Override
    public void get(ImportedClass someParams) throws Exception
    {
        SomeTypes types = someTypesList.getFirstAndRotate();

        switch(types)
        {
            case SAMPLE01:
            someOtherClassProcessor01.doSomething(someParams,     date);
            break;
            case SAMPLE02:
            someOtherClassProcessor02.doSomething(someParams,     date);
            break;
            case SAMPLE03:
            someOtherClassProcessor03.doSomething(someParams,     date);
            break;
            default:
            throw new IllegalArgumentException("This " + types + "     was not implemented.");
        }
    }   
}

For my test this is what I have so far... not sure how to actually do it.

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class)
public class TestingMyClass
{
    MyClass mockMyClass;
    SomeOtherClassProcessor01 someOtherClassProcessor01;
    SomeOtherClassProcessor02 someOtherClassProcessor02;
    SomeOtherClassProcessor03 someOtherClassProcessor03;
    Date date;


    @Before
    public void initialize () throws Exception
    {
        mockMyClass = spy(new MyClass()); 
        mockSomeOtherClassProcessor01 =     mock(SomeOtherClassProcessor01.class);
        mockSomeOtherClassProcessor02 =     mock(SomeOtherClassProcessor02.class);
        mockSomeOtherClassProcessor03 =     mock(SomeOtherClassProcessor03.class);
    }

    @Test
    public void testingGet() throws Exception
    {
        date = new Date(); 
        //this is where I'm stuck
        Whitebox.setInternalState(mockMyClass,     "someOtherClassProcessor01", mockSomeOtherClassProcessor01);

    }
}

Would it be possible to use whitebox for this? I need to make sure that there's a call inside the getter for those objects. Should I try something like when(someOtherClassProcessor01.doSomething(any(), date)).thenReturn(true)? Please let me know if you need more details.

edit: is even possible to mock private enum SomeTypes?

iluxa :

One option is to substitute your own (mocked) implementations of SomeOtherClassProcessor into MyClass using reflection:

MyClass myClass = new MyClass();
SomeOtherProcessor01 mockProcessor01 = mock(SomeOtherProcessor01.class);

// reflection bit: find the field by its name
// handle NoSuchFieldException
Field someProcessorField = MyClass.getDeclaredField("someOtherProcessor01");
// the field is declared as private, so make it accessible in order to work with it
someProcessorField.setAccessible(true);
// now set your mocked processor into the field. 
// First argument is the object to change; second argument - new value for the field
someProcessorField.set(myClass, mockProcessor01);

PS. Using PowerMock and/or reflection is surrender to bad design (as per Timothy :). You should not be depending on code you that isn't already well-tested, and if it is, you shouldn't try to test it again. Suppose your testing actually reveals a bug - how would you fix it if you don't control the code? Suppose Java 11 becomes a thing and prohibits your use of reflection. Suppose the code you're testing changes and the fields get renamed - with reflection, you don't have compile-time safety... List of potential issues goes on

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325443&siteId=1