Testing protected method with JUnit
Asked Answered
R

6

18

I am testing a method which is protected. In my test case I've used Reflection to access the method but I am not exactly sure whether I am doing it in a right way.

Method to be tested:

protected void checkORCondition( Map<String, Message> messagesMap ) throws EISClientException
{
    Message message = containsAMessageCode(getMessageCodes(), messagesMap);
    if(message!=null)
    {
        throw new EISClientException("One of the specified message code matched returned errors." + 
                message.getMessageCode() + ": " + message.getMessageType() + ": " + message.getMessageText());

    }
}

JUnit test case:

@Test
public void testcheckORCondition() throws Exception {
    Class clazz = MessageToExceptionPostProcessFilter.class;
    Object object = clazz.newInstance();

    Method method = clazz.getDeclaredMethod("checkORCondition", new Class[]{Map.class});
    method.setAccessible(true);

    String string = new String();
    string = "testing";

    Message message = new Message();
    message.setMessageCode("200");

    Map<String, Message> map = new HashMap<String, Message>();
    map.put(string, message);

    assertEquals("testing", string);
    assertEquals("200", message.getMessageCode());  
}

My JUnit passes but not sure if it going inside the method.

Reprovable answered 3/2, 2016 at 20:6 Comment(1)
Do you have other methods in the same class that call the protected method? It is acceptable just to test public methods in a class, since those should define the behavior of the object.Soccer
D
33

Best way is to put the protected methods under same package name under test. This will ensure that they are accessible. Check junit FAQ page http://junit.org/faq.html#organize_1

Dropsonde answered 3/2, 2016 at 20:11 Comment(0)
R
9

Using reflection to access protected methods from a unit test seems heavy handed. There are several easier ways to do this.

The easiest way would be to make sure your tests are in the same package hierarchy as the class you are testing. If that's not possible then you can subclass the original class and create a public accessor that calls the protected method.

If it's a one-off case then it could even be as simple as making an anonymous class.

Class you want to test:

public class MessageToExceptionPostProcessFilter {

    protected void checkOrCondition(Map<String, Message> messagesMap) throws EISClientException {
        // Logic you want to test
    } 
}

And your test class:

public class MessageToExceptionPostProcessFilterTest {
    @Test
    public void testCheckOrCondition() throws Exception {
        String string = "testing";

        Message message = new Message();
        message.setMessageCode("200");

        Map<String, Message> map = new HashMap<>();
        map.put(string, message);

        MessageToExceptionPostProcessFilter filter = new MessageToExceptionPostProcessFilter() {
            public MessageToExceptionPostProcessFilter callProtectedMethod(Map<String, Message> messagesMap) throws EISClientException {
                checkOrCondition(messagesMap);
                return this;
            }
        }.callProtectedMethod(map);

        // Assert stuff
    }
}
Rave answered 26/7, 2018 at 18:11 Comment(0)
M
5

Make sure you have the same package name for your unit test cases similar to where your actual code resides. This will allow protected methods to be able to access properly in unit test cases.

Mcgruter answered 14/11, 2020 at 1:44 Comment(0)
K
2

It doesn't go inside the method as you don't call it. Use invoke to call it:

method.invoke(this_parameter, new Object[]{ map });

Other than that, there is no good solution. One recommendation is to put the test into the same package and make it package visible, but there are lot of cons as the method will not be visible by inherited classes.

I believe the way you chose is good one.

Kerby answered 3/2, 2016 at 20:14 Comment(2)
Zbynek, thank you for your help. Seems like it went through and even Cobertura report recognized it.Reprovable
@Yousuf : maybe it went through but definitely not as part of this unit test. Unless called from constructor of course. Simply there is no call to that method.Kerby
A
0

Use a mocking library to create a subclass as part of your test.

Aft answered 3/2, 2016 at 20:10 Comment(0)
L
0

If you cannot or don't want to have a test class in the same package as a tested class, you can simply create your own custom class (directly in a test class), and simply extends from tested class. Then override protected methods of a tested class, and just call implementations from super class. In this case you will be able to call methods from the custom class, which will call methods from a tested class.

class classYouWantToTest {
    protected void methodA(){}
}

class unitTest {
    private static final class B extends A {
        protected void methodA(){
            super.methodA();
        }
    }

    public test() {
        var b = new B();
        b.methodA();
    }
}
Liverpudlian answered 14/6 at 12:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.