【问题标题】:How to mock static method in Java?如何在 Java 中模拟静态方法?
【发布时间】:2013-03-15 18:24:01
【问题描述】:

我有一个类 FileGenerator,我正在为 generateFile() 方法编写一个测试,该方法应该执行以下操作:

1) 它应该在BlockAbstractFactory 上调用静态方法getBlockImpl(FileTypeEnum)

2) 它应该从子类方法getBlocks() 填充变量blockList

3) 它应该从最终的辅助类 FileHelper 调用静态方法 createFile,并传递一个字符串参数

4) 它应该调用blockList中每个BlockController的run方法

到目前为止,我有这个空方法:

public class FileGenerator {
    // private fields with Getters and Setters

    public void generateBlocks() {
    }
}

我正在使用 JUnit、Mockito 来模拟对象,并且我尝试使用 PowerMockito 来模拟静态类和最终类(Mockito 不这样做)。

我的问题是:我的第一个测试(从BlockAbstractFactory 调用方法getBlockList())通过了,尽管generateBlocks() 中没有实现。我已经在BlockAbstractFactory 中实现了静态方法(目前返回null),以避免Eclipse 语法错误。

如何测试静态方法是否在fileGerator.generateBlocks()内被调用?

到目前为止,这是我的测试课:

@RunWith(PowerMockRunner.class)
public class testFileGenerator {
    FileGenerator fileGenerator = new FileGenerator();

    @Test
    public void shouldCallGetBlockList() {
            fileGenerator.setFileType(FileTypeEnum.SPED_FISCAL);

            fileGenerator.generateBlocks();

            PowerMockito.mockStatic(BlockAbstractFactory.class);
            PowerMockito.verifyStatic();
            BlockAbstractFactory.getBlockImpl(fileGenerator.getFileType());
    }
}

【问题讨论】:

  • 抽象方法不能是静态的
  • 最简单的答案是,如果您决定进行 TDD,请改掉编写静态方法的习惯 :)
  • @ArtB 它是来自抽象类的静态方法,而不是抽象静态方法。编辑:刚刚看到我的问题中的错误。固定。
  • @Affe 好吧,如果真的没有其他办法,我会改变它......
  • 不是您问题的答案,只是一个提示:在您的测试方法或@Before 中实例化您的FileGenerator fileGenerator = new FileGenerator();,而不是作为您的测试类的成员。使用您当前的实现,您将在测试类中的测试上共享实例化的fileGenerator(假设您还需要独立测试)

标签: java junit tdd mockito powermock


【解决方案1】:

我没有使用 PowerMock 的经验,但是由于您还没有得到答案,所以我一直在阅读文档,看看能否在您的路上为您提供一些帮助。

我发现你需要准备 PowerMock 以便我知道它需要准备哪些静态方法才能被模拟。像这样:

@RunWith(PowerMockRunner.class)
@PrepareForTest(BlockAbstractFactory.class) // <<=== Like that
public class testFileGenerator {
    // rest of you class
}

Here你可以找到更多信息。

这有帮助吗?

【讨论】:

  • 谢谢!!当我添加@PrepareForTest 以及我的测试类扩展TestCase 时,它​​起作用了!这是完整的解决方案:@RunWith(PowerMockRunner.class) @PrepareForTest(BlockAbstractFactory.class) public class testFileGenerator extends TestCase { // same code, with your @Before and @After suggestion }
  • @user1042273 嘿,不错!不过提醒一下 Affe 的评论。静态方法是 TDD 的一大痛点。小心使用它们。如果您要向静态类/公共静态方法添加状态,您将很难对它们进行 TDD。你会到达那里,谢谢你的问题,我从来没有听说过可以处理静态类的模拟框架:)。我会赞成的。干杯,玩得开心!
  • 另一个需要考虑的问题是,模拟静态方法需要在运行时进行字节码操作,并且会降低性能。如果你只模拟一两个静态方法,你可能会没事,但如果你经常这样做,你真的会减慢你的测试。
  • @bcarlso 通过CGLIB 创建新的子类,所有其他模拟工具都这样做,需要在运行时进行字节码操作吗?我真的看不出有什么不同...
  • @Rogerio 也许也可以。在模拟标准方法与静态方法时,我经历了性能上的显着差异。我不知道细节,所以它可能不是字节码操作。谢谢你让我理顺。我将不得不更多地研究差异。
【解决方案2】:

工作示例:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassStaticA.class, ClassStaticB.class})
public class ClassStaticMethodsTest {

    @Test
    public void testMockStaticMethod() {
        PowerMock.mockStatic(ClassStaticA.class);
        EasyMock.expect(ClassStaticA.getMessageStaticMethod()).andReturn("mocked message");
        PowerMock.replay(ClassStaticA.class);
        assertEquals("mocked message", ClassStaticA.getMessageStaticMethod());
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    相关资源
    最近更新 更多