Powermock, Mockito调用super()时出现NullPointerException异常,JDialog

11

当我尝试对JDialog对象中的一些方法进行单元测试时,我遇到了NullPointerException。除了调用静态方法之外,我还必须初始化对话框父级的模拟版本以及将要使用的另一个类(代码如下):

@RunWith( PowerMockRunner.class )
@PrepareForTest( ControlFileUtilities.class )
public class StructCompDlgTest 
{
  @Before
  public void setUp() throws Exception
  {
    controlFrame    = org.mockito.Mockito.mock( ControlFrame.class );
    structCmpDlg    = new StructureCompareDialog( controlFrame );
    serverPipeline  = org.mockito.Mockito.mock( ServerPipeline.class );
  }
...
}

构建对话框的代码如下所示:
StructureCompareDialog( IControlFrame controlFrame )
{
 super( (Frame) controlFrame, "title", true );
 ...
}

当调用超级构造函数时,我最终会在java.awt.Window.addOwnerWindow(Window.java:2525)处收到NullPointerError错误。
void addOwnedWindow(WeakReference weakWindow) {
  if (weakWindow != null) {
    synchronized(ownedWindowList) {  ***<<------ offending line***
      // this if statement should really be an assert, but we don't
      // have asserts...
      if (!ownedWindowList.contains(weakWindow)) {
        ownedWindowList.addElement(weakWindow);
      }
    }
  }
}

我知道我在混淆静态和swing gui,但我别无选择。我被要求使用现有的代码编写一些单元测试,但我不知道出了什么问题。

谢谢


你最终解决了这个问题吗?如果是的话,能否麻烦您发布一下解决方案? - glenneroo
奇怪的是,在synchronized(ownedWindowList)处出现了空指针异常。如果您检查Window.java中的ownedWindowList数据成员,它已经被实例化并且从未再次赋值为null。想知道什么可能会使这个数据成员变为null。您能否在代码中检查此数据成员是否被访问(使用反射)并已更改为null。最不可能的情况是需要手动更改此数据成员,但最好确保一下。 - Yogesh Ralebhat
@glenneroo,我认为在这里设置赏金而不是使用自己的代码创建新问题是一个错误。您能否提供一些详细信息,例如您正在做什么以及异常的堆栈跟踪? - SergGr
@SergGr,你可能是对的,我的配置略有不同(没有PowerMockRunner),但异常和位置相同。堆栈跟踪似乎并不是很有帮助,但我会创建另一个问题,并希望它不会被标记为重复。 - glenneroo
@glenneroo,实际上,将这个问题的链接添加进来并提到您还没有解决问题可能会很有用。 - SergGr
3个回答

5

看起来有些棘手!实际上,您需要找到在构造函数中调用的所有controlFrame方法,并添加一些调用。

when(controlFrame.methodCalled()).thenReturn(somethingSensible);

如果这看起来像一项艰巨的任务,那么尝试创建一个默认实现的 IControlFrame,并将其作为测试 setUp() 的一部分创建,使用它代替模拟可能会更好。
我之前遇到过类似的问题,当时我正在尝试对 Spring JMS 监听器进行单元测试。正确或错误地说,我通过创建自己的 DefaultMessageListenerContainer 默认实现解决了这个问题,这与您描述的问题类似。我的解决方案涉及扩展真实实现并添加自己的测试特定版本,如下所示。
/**
 * Empty mocked class to allow unit testing with spring references to a
 * DefaultMessageListenerContainer. The functionality on this class should never be
 * called so just override and do nothing.  
 */
public class MockDefaultMessageListenerContainer extends DefaultMessageListenerContainer {

    public MockDefaultMessageListenerContainer() {
    }

    public void afterPropertiesSet() {
    }

    @Override
    protected Connection createConnection() throws JMSException {
        return null;
    }
}

在我的示例中,我通过将一个null值传回到有问题的createConnection()方法来使我的测试运行起来。也许相同的方法可以帮助您。

0

我不知道你的 IControlFrame 长得什么样,但把模拟的 Frame 传给 super() 是行不通的。我不得不实例化自己的版本:

private class EmptyControlFrame extends JFrame implements IControlFrame {

    @Override
    public JFrame getFrame() {
        return null;
    }

    // return null for any other overrides from IControlFrame
}

然后在你的setUp()函数中:

controlFrame = new EmptyControlFrame();

0

ownedWindowListjava.awt.Window 类中的 transient。你的 JDialog 实例是否被序列化了?如果是,你可能需要使用 Serializable 接口中的 readObject(java.io.ObjectStream) 方法来重新初始化 ownedWindowList


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接