Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 类的私有静态final字段中的模拟静态方法调用_Java_Junit_Powermock_Easymock - Fatal编程技术网

Java 类的私有静态final字段中的模拟静态方法调用

Java 类的私有静态final字段中的模拟静态方法调用,java,junit,powermock,easymock,Java,Junit,Powermock,Easymock,我有一个基本的Widget类,它使用实用类Utils public class Widget { private static final String BUTTON_KEY = Utils.getMessage("btn-key"); public boolean comp() { String specialKey = Utils.getMessage("special-key"); return specialKey.equals(BUT

我有一个基本的
Widget
类,它使用实用类
Utils

public class Widget {

    private static final String BUTTON_KEY = Utils.getMessage("btn-key");

    public boolean comp() {
        String specialKey = Utils.getMessage("special-key");
        return specialKey.equals(BUTTON_KEY);
    }

}

class Utils {

    public static String getMessage(String key) {
        return key + " : message";
    }

}
我想为
comp
方法创建一个测试

我的测试是这样的

@RunWith(PowerMockRunner.class)
@PrepareForTest(Utils.class)
public class WidgetTest {

    private Widget widget;

    @Before
    public void setUp() {
        mockStatic(Utils.class);
        widget = new Widget();
    }

    @Test
    public void testComp() {
        expect(Utils.getMessage("btn-key")).andReturn("btn-key : message");
        expect(Utils.getMessage("special-key")).andReturn("special-key : message");
        replayAll();
        assertFalse(widget.comp());
        verifyAll();
    }

}
这项测试失败了

java.lang.IllegalStateException: missing behavior definition for the preceding method call:
Utils.getMessage("btn-key")
Usage is: expect(a.foo()).andXXX()
如果我删除常量字段中的方法调用(并因此删除对它的期望),测试将成功

问题出在哪里?

一般性评论 在回答其他问题之前,请先阅读这篇哲学评论

我经常遇到可测试性差的代码。我们有Spring,我们有依赖注入,为什么我们仍然觉得需要使用静态方法和实用程序类

当你想使用PosiMoCK时,首先考虑一下代码的一个小的重构不会对你有什么帮助。


您需要模拟您的方法这一纯事实意味着该方法不是真正静态的。嗯,也许
Math.sqrt()
Assert.assertEquals()
是真正静态方法的好例子

另一方面,一些乍一看可能是“静态”的方法在您开始考虑测试时就会暴露出来,例如
LocalDate.now()
。在测试中,需要静态的是当前日期,而不是方法:)

这里有很多好主意:


你的问题 问题在于,在开始定义期望值之前,会调用
小部件
类的静态初始值设定项

如果将此代码添加到
小部件
类的任意位置,您可能会看到:

static {
    System.out.println("Widget.static");
}
将此代码添加到
widgetest.testComp()方法的开头:

public void testComp() throws Exception {
    System.out.println("test method");
    ... // the rest of the method
}
运行测试时,输出如下所示:

Widget.static
test method
这意味着
BUTTON\u KEY=Utils.getMessage(“btn KEY”)
expect(Utils.getMessage(“btn KEY”))之前执行和PowerMock正确地抱怨缺少行为定义


可能的快速解决方案 如果您想保持静态逻辑,有一个快速的解决方法。不要在静态初始化程序块中启动BUTTON_键,而是延迟启动

我不太喜欢它,我仍然喜欢完全摆脱静态调用

我在代码中留下了test
println()
s,以便您可以看到调用的顺序

public class Widget {
    private static String BUTTON_KEY;

    static {
        System.out.println("Widget.static");
    }

    public boolean comp() {
        String specialKey = Utils.getMessage("special-key");
        return specialKey.equals(getButtonKey());
    }

    private static String getButtonKey() {
        synchronized (Widget.class) {
            if (BUTTON_KEY == null) {
                System.out.println("Widget is calling Utils.getMessage(`btn-key`)");
                BUTTON_KEY = Utils.getMessage("btn-key");
            }
        }
        return BUTTON_KEY;
    }
}

class Utils {
    public static String getMessage(String key) {
        return key + " : message";
    }
}
调用的顺序如下:

Widget.static
test method
Widget is calling Utils.getMessage(`btn-key`)

这个方法是静态的,因为它是实用程序类的一部分,允许从
.properties
文件获取消息。因此,基本上我必须删除常量或其他东西…@lapots查看我的编辑-我提供了一个链接,指向如何将Util类转换为可测试的类。或者只需搜索谷歌:
Java如何将静态实用程序类转换为可测试类
。修复类以使其在没有PowerMock的情况下是可测试的,而不是尝试进行变通,这是更好的时间投资。PowerMock本身就是一个解决方案:)问题是实用程序类不是我的,而是外部依赖。我们最多只能将initialize移到方法中的一些变量上,“您需要模拟您的方法这一纯粹事实意味着该方法不是真正静态的”。切中要害+1.@ShanuGupta在某些类中,我确实会将其模拟为静态的,也会模拟为真实的。但我对此无能为力。唯一的解决方法我不敢说,但是由于
按钮_键
的静态初始化,您的
小部件
类是不可测试的。