非静态方法的 GroovyMock 是否具有指定的行为?

Does a GroovyMock of a non-static method have a specified behaviour?

我把它放在我的 Spock 测试中:

GroovyMock( File, global: true)
File.createNewFile() >> null

...我意识到 unorthodox/silly/curious:createNewFile 是一种非静态方法。

涉及到的代码是这样的:

if( indexInfoFile.createNewFile() ) {

...从我的经验来看,像这样模拟 createNewFile 总是 returns false,即使你尝试在模拟中放置一个块:

GroovyMock( File, global: true)
File.createNewFile() >> {
    log.info( 'Hello mum!')
}

...日志消息未打印,但再次 createNewFile returns false.

这正是我想要的(即从 createNewFile 模拟 false return)。

这是有记录的故意行为吗?

PS 警告:从我今天的 experience/experiments 开始,毫无疑问,这个模拟方法确实替换了任何 File 实例上对该方法的所有调用。然而,它似乎也有一些令人担忧的副作用:例如,我在我的 given 块中创建的目录在 2 GroovyMock 行之前找到 NOT 之后存在,仍然在 given 块中,当我去

myDirPath.toFile().exists()

...我认为这是因为 toFile 涉及对 createNewFile...

的调用

documented 一样,Groovy 模拟在与 Groovy classes 一起使用时只有额外的 "magic",但我假设您正在尝试模拟java.io.File,这是一个 Java JRE class。因此,Groovy 模拟将表现得像一个普通的 Spock 模拟。所以我不知道你为什么首先要使用 Groovy 模拟 - 可能是因为你想使用 global: true 功能以避免在你的应用程序中重构可测试性 class.

因为你没有给我们看 MCVE,我无法知道 indexInfoFile 是否可以注入到你正在测试的 class/method 中,或者它是否是内部创建的依赖项方法。在后一种情况下你需要重构,就这么简单。依赖项应该是可注入的,期间。

至于您的代码片段,它们存在一些问题:

  • 方法File.createNewFile()returnsboolean,所以存根到returnnull.
  • 没有任何意义
  • 创建模拟时,所有方法将自动 return falsenull0,具体取决于它们的 return 类型。因此,如果您想要 return false,则无需首先存根 createNewFile() 的结果,因为它已经存在。
  • 您不能通过像静态方法一样尝试覆盖它来存根实例方法。这没有道理。请先学习 Spock 语法。

现在,假设您的 class 测试看起来像这样(已经通过方法参数、构造函数参数或 setter 准备或重构依赖注入)...

package de.scrum_master.Whosebug.q59842227;

import java.io.File;
import java.io.IOException;
import java.util.Random;

public class FileCreator {
  private static final Random RANDOM = new Random();

  public boolean createIndexInfoFile(File indexInfoFile) throws IOException {
    if (indexInfoFile.createNewFile()) {
      System.out.println("File \"" + indexInfoFile + "\" created");
      return true;
    }
    System.out.println("File \"" + indexInfoFile + "\" NOT created");
    return false;
  }

  public static void main(String[] args) throws IOException {
    new FileCreator().createIndexInfoFile(
      new File("_abc_" + RANDOM.nextInt(10000) + ".txt")
    );
  }
}

...那么你可以这样测试:

package de.scrum_master.Whosebug.q59842227

import spock.lang.Specification

class FileCreatorTest extends Specification {
  def "index info file created"() {
    given:
    File file = Mock() {
      createNewFile() >> true
    }

    expect:
    new FileCreator().createIndexInfoFile(file)
  }

  def "no index info file created"() {
    given:
    File file = Mock()

    expect:
    !new FileCreator().createIndexInfoFile(file)
  }
}

看到了吗?不需要全局或 Groovy 模拟,普通模拟就可以了。但是您需要使您的代码可测试,而不是使用花哨的技巧。