非静态方法的 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
false
、null
或 0
,具体取决于它们的 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 模拟,普通模拟就可以了。但是您需要使您的代码可测试,而不是使用花哨的技巧。
我把它放在我的 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
false
、null
或0
,具体取决于它们的 return 类型。因此,如果您想要 returnfalse
,则无需首先存根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 模拟,普通模拟就可以了。但是您需要使您的代码可测试,而不是使用花哨的技巧。