【问题标题】:Mocking getResource in static block with PowerMock使用 PowerMock 在静态块中模拟 getResource
【发布时间】:2017-12-17 09:46:53
【问题描述】:

如何在静态块中模拟getResourceAsStream? 我认为这是无法测试的。

我查看了 SO,但找不到答案。 closes-SO-post-here 没有解决该问题,因为帖子中对 getResourceAsAStream 的调用不是来自静态块

我尝试了 PowerMock,但遇到了许多限制。首先,如果我想模拟SomeProperties.class.getResourceAsStream - 将执行静态块,因为我需要引用类本身。我可以抑制静态块以防止这样做,但这将阻止我让静态块执行。解决方案是将静态块的执行推迟到 someProperties.class.getResourceAsStream 被模拟之后。 我不认为这是可能的。 看来这段代码纯粹是无法测试的; 还有其他想法吗?

这里是代码 [and a link to GITHUB]:

package com.sopowermock1;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class SomeProperties {

    private static Properties props = new Properties();

    static {
        InputStream is = SomeProperties.class.getResourceAsStream("/some.properties");

        try {
            props.load(is);
            System.out.println("Properties.props.keySet() = " + props.keySet());            
        } catch (IOException e) {
            // How test this branch???
            System.out.println("Yes. We got here.");
            throw new RuntimeException(e);
        }
    }

    private SomeProperties() {}; // to makes life even harder...

    public static String getVersion() {
        return props.getProperty("version");
    }
}

这是测试GITHUB Link

package com.sopowermock1;
import java.io.InputStream;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.sopowermock1.SomeProperties;

@RunWith(PowerMockRunner.class)
@PrepareForTest(SomeProperties.class)

// This will prevent running static block completely:
// @SuppressStaticInitializationFor("com.sopowermock1.SomeProperties")
public class SomePropertiesTest {

    @Mock
    private static InputStream streamMock;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(SomeProperties.class);
        System.out.println("test setUp");
    }

    @Test(expected = RuntimeException.class)
    public void testStaticBlock() {

        PowerMockito.mockStatic(SomeProperties.class); // this will mock all static methods (unwanted as we want to call getVersion)

        // This will cause static block to be called.
        PowerMockito.when(SomeProperties.class.getResourceAsStream("/some.properties")).thenReturn(streamMock);
        SomeProperties.getVersion();
    }
}

有什么想法吗?完整的 GITHUB 源是here

【问题讨论】:

  • 那么如果这段代码是不可测试的,你为什么不重构它使其可测试呢?具体来说,您可以将对 getResourceAsStream 的调用移至其自己的方法,然后您可以存根。
  • 一般来说,使用静态块/静态函数进行测试是有问题的,因为试图模拟它们会导致使用非常具有侵入性或过于复杂的工具。重构代码以避免静态问题通常要简单得多。
  • 我已经考虑过重构。自从我开始使用 PowerMock 后,我就想从这个工具中获得更多。
  • 无论何时使用SomeProperties.class,都会执行静态初始化程序。您可以将类注释更改为@PrepareForTest(fullyQualifiedNames = "com.sopowermock1.SomeProperties"),但我看不出在mockStatic 中使用该类。可能您可以尝试在测试中抑制初始化程序,然后通过单独的类加载器再次调用初始化程序。

标签: java unit-testing junit powermock static-block


【解决方案1】:

How to mock getResourceAsStream method using PowerMockito and JUnit?中提到的,使用Extract Delegate,然后模拟XXStreamFetcher等委托类,然后就可以测试了。

【讨论】:

    猜你喜欢
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    • 2012-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多