使用JMockit进行模拟会对内部类的局部变量抛出NullPointerException

时间:2015-01-16 22:12:58

标签: unit-testing nullpointerexception jmockit

我正在尝试模拟一个创建局部变量的方法,尝试一些东西,并在抛出异常时进行记录。这是一段代码:

public void myFunction() {
    //Some stuff
    try {
        new File("foo").getAbsoluteFile();
    } catch (SecurityException e) {
        //Do some logging
    }
}

我想使用JMockit模拟这种日志记录行为(如果重要的话,使用1.8版)。所以我创建了以下测试:

@Test(expected=SecurityException.class)
public void testAbsoluteFile(
        @Injectable final File file
) throws IOException {

    new Expectations(File.class){{
        new File(anyString);
        result = file;
        file.getAbsoluteFile();
        result = new SecurityException();
    }};

    myFunction();
}

麻烦的是,这似乎给了NullPointerException关于File.getAbsoluteFile()的内部运作,我觉得这绝对是奇怪的:

java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NullPointerException>
Caused by: java.lang.NullPointerException
    at java.io.Win32FileSystem.slashify(Win32FileSystem.java:56)
    at java.io.Win32FileSystem.resolve(Win32FileSystem.java:330)
    at java.io.File.getAbsolutePath(File.java:556)
    at java.io.File.getAbsoluteFile(File.java:572)
    at com.vue.rescoreservice.ExpectationTest.myFunction(ExpectationTest.java:39)
    at com.vue.rescoreservice.ExpectationTest.testAbsoluteFile(ExpectationTest.java:33)

这似乎很奇怪,因为它说Win32FileSystem类中的局部变量(不是典型Java API中的内部类)抛出NullPointerException,而以前从未发生过。

堆栈跟踪中的行如下:

//In myFunction()
new File("foo").getAbsoluteFile();

//In testAbsoluteFile()
myFunction();

为什么会这样?我怎样才能使JMockit不在内部类的局部变量上抛出NullPointerException?

2 个答案:

答案 0 :(得分:3)

该问题已在最新的jMockit版本(1.14)中修复。如果您现在不想迁移,可以在1.8中修复测试(请参阅下面的代码)。

在这种情况下,不需要@Injectable。 File的构造函数被模拟为Expectations,并且需要模拟类本身而不是单个实例。在这种情况下,行为等同于@Mocked(但根据Expectations块中的调用,将部分模拟File)。

myFunction中的catch子句需要重新抛出SecurityException以允许测试通过。

@Test(expected=SecurityException.class)
public void testAbsoluteFile() throws IOException {
    new Expectations(File.class) {{
        File file = new File(anyString);

        file.getAbsoluteFile();
        result = new SecurityException();
    }};

    myFunction();
}

如果您希望将mock声明为参数,它也可以工作,但File不会被部分模拟(所有方法都将被模拟)。

@Test(expected=SecurityException.class)
public void testAbsoluteFile(@Mocked final File file) throws IOException {

    new Expectations(){{
        new File(anyString);

        file.getAbsoluteFile();
        result = new SecurityException();
    }};

    myFunction();
}

答案 1 :(得分:1)

@ Marc-André的最新消息。

在我使用JMockit 1.25的情况下,我不得不在期望之外定义文件变量,如下所示:

footerFirstColumn

在回答之前,可能是对JMockit的改变。