1

The method I am writing unit test for has a method call that refers to a method In another class which is an abstract class. That method is called recursively, which is giving a stack overflow error when I execute my test case.

Below is the method under test

public void configure(Hashtable config) throws PipeBrokenException
  {
    // Configure the Pipe Element ...
    _source = (String) config.get(this.IMAGE_SOURCE);
    _destination = (String) config.get(this.IMAGE_DESTINATION);
    _printer = (XrayPrinterIf) config.get(this.PRINTER_INTERFACE);
    _configProvider = (AutoPrintConfigProvider) config.get(this.AUTOPRINT_CONFIG_PROVIDER);
     TraceLogger.getApplicationLogger().info("AutoPrintEndPoint Configure.. useTaskManager = " +useTaskManager);
    if(useTaskManager)
    {
        mgr = new AutoPrintTaskManager(this);
    }
    super.configure(config);//this method call gives a stack overflow error, when I comment this my test case runs fine.
  }

Below is the definition of the method call super.configure(config);, the class containing this method is an abstract class, and this method is called recursively endlessly giving me stack over flow error.

This method defined in public abstract class AnAbstractClass

public abstract class AnAbstractClass{
public void configure(Hashtable properties) throws PipeBrokenException
  {
    if( _nextNode != null)
    {
      _nextNode.configure(properties);
    }
  }
}

This is my JUnit test case, I am still an amateur at this and learning, please feel free to correct me wherever I am wrong and hopefully resolve the error I am facing.

@InjectMocks
    AutoPrintEndPoint autoPrintEndPoint = PowerMockito.spy(new AutoPrintEndPoint("pipeName")); //AutoPrintEndPoint is the class under test
@Test
    public void testConfigureHashtable() throws PipeBrokenException 
    {
      //  SmartPipeNode node=Mockito.mock(SmartPipeNode.class,Mockito.CALLS_REAL_METHODS);

        AutoPrintConfigProvider autoPrintConfigProvider=Mockito.mock(AutoPrintConfigProvider.class); //AutoPrintConfigProvider is an interface
        XrayPrinterIf _printerIf=Mockito.mock(XrayPrinterIf.class);//XrayPrinterIf  is an interface
        Hashtable config=new Hashtable();
        config.put(AutoPrintEndPoint.IMAGE_SOURCE,"Source");
        config.put(AutoPrintEndPoint.IMAGE_DESTINATION,"Destination");
        config.put(AutoPrintEndPoint.PRINTER_INTERFACE,_printerIf);
        config.put(AutoPrintEndPoint.AUTOPRINT_CONFIG_PROVIDER,autoPrintConfigProvider);
        autoPrintEndPoint.configure("useTaskManager","yes");

        //Mockito.doNothing().when(autoPrintEndPoint).configure(config);


        autoPrintEndPoint.configure(config);
        String _source=Whitebox.getInternalState(autoPrintEndPoint, "_source");
        String _destination=Whitebox.getInternalState(autoPrintEndPoint, "_destination");
        System.out.println(_destination+"hello destination");
        System.out.println(_source+"here");
    }

Stack Trace

java.lang.StackOverflowError
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$100(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:178)
    at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:68)
    at java.lang.ClassLoader.loadClass(Unknown Source)
9
  • Could you include the stack trace? Commented Mar 24, 2017 at 9:15
  • @NikolaStojiljkovic I have added the stack trace Commented Mar 24, 2017 at 9:27
  • Sorry, seems that I am too tired resp. too much in need for coffee. But OK, then you have to step back and provide a real minimal reproducible example; as it is absolutely essential to understand where that autoPrintEndPoint` is coming from. Commented Mar 24, 2017 at 9:56
  • alright sorry about that. I will edit my post and mention it. I guess I did not notice that I omitted that detail. Commented Mar 24, 2017 at 9:58
  • autoPrintEndPoint.configure("useTaskManager","yes"); this I call to go inside the if condition and to check if the variable mgr is initialized or not. Commented Mar 24, 2017 at 10:17

3 Answers 3

1

Since you are using PowerMockito you should be able to suppress any calls to methods in AnAbstractClass with:

PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(AnAbstractClass.class));
Sign up to request clarification or add additional context in comments.

3 Comments

I am getting an error in methodsDeclaredIn part of the syntax
Sorry should have mentioned its a static method of MemberMatcher
yes this works, but wouldn't it be violating the design of the implementation, should someone delete that method call in future, that I have suppressed, then my test case should fail since I am testing every possibility. If I suppress then my test case will pass even when the implementation is modified.
0

_nextNode refers to this.

Add a check:

if (_nextNode != null && _nextNode != this) {
  _nextNode.configure(properties);
}

If circular links are possible, you'll have to keep track of all nodes visited in a Set and check that you're not visiting a node again.

7 Comments

Unfortunately I cannot modify the implementation.
Can you set _nextNode? Either by a setter or a constructor parameter?
yes I have a setter to set _nextNode. but even after I set it I am getting stack overflow error.
What do you set it to?
i set it to the mock object of the abstract class. The set method is also declared in the abstract class.
|
0

I created a thread to control the number of times the recursive call is taking place. and within the thread I have set the variable _nextNode with the mock object of the class which extends the abstract class that contains the recursive method. After the method is called the number of times specified then the variable _nextNode is set to null. I hope this answer will be useful. below is the piece of code that I wrote to rectify the stack overflow error in my case

AutoPrintEndPoint autoPrintEndPointMock = Mockito.mock(AutoPrintEndPoint.class);
        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    autoPrintEndPoint.setNextNode(autoPrintEndPointMock); 
                }
                autoPrintEndPoint.setNextNode(null);

            }
        }.start();
        autoPrintEndPoint.configure(config);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.