Akhil Vijayan
Akhil Vijayan

Reputation: 119

stack overflow error while executing JUnit test case

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)

Upvotes: 1

Views: 2188

Answers (3)

Akhil Vijayan
Akhil Vijayan

Reputation: 119

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);

Upvotes: 0

Plog
Plog

Reputation: 9622

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

PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(AnAbstractClass.class));

Upvotes: 1

Bohemian
Bohemian

Reputation: 425073

_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.

Upvotes: 0

Related Questions