Spock 测试方法是否被构造函数调用
Spock test if method was called by constructor
我有一个 Firebase 管理助手 class,我正在使用 Spock 进行测试。这个 class 的构造函数会在必要时调用 class 中的另一个方法来初始化某些字段,如下所示:
public class FirebaseUtility {
private static FirebaseDatabase db = null;
public FirebaseUtility() throws IOException {
if (db == null) {
initializeFirebase();
}
}
public void initializeFirebase() throws IOException {
InputStream serviceAccount = ClassLoader.getSystemResourceAsStream("serviceAccount.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("<my_database_url>").build();
FirebaseApp.initializeApp(options);
db = FirebaseDatabase.getInstance();
}
}
基本上,如果已经设置了 FirebaseDatabase,则执行所有初始化代码是没有意义的。
我试过这样做,但似乎不起作用:
class FirebaseUtilitySpec extends Specification {
def "instantiating FirebaseUtility should run initialization code"() {
given:
def f
when:
f = new FirebaseUtility()
then:
1 * f.initializeFirebase()
}
}
首先,您无法检查原始对象的交互,您需要使用模拟或间谍。此外,这些类型的对象无法拦截静态方法或构造函数上的交互。为此,您必须将 Mockito 甚至 PowerMock 添加到组合中。但基本上,静态方法无论如何都是丑陋的,并且没有必要在构造函数调用中初始化静态成员。只需对数据库对象使用惰性 getter 并拦截其行为。
我稍微简化了您的示例,删除了外部依赖项并仅模拟 Firebase,以便更容易回答 MCVE:
package de.scrum_master.Whosebug;
public class FirebaseDatabase {
private static FirebaseDatabase instance;
public static FirebaseDatabase getInstance() {
if (instance == null)
instance = new FirebaseDatabase();
return instance;
}
}
package de.scrum_master.Whosebug;
public class FirebaseUtility {
private static FirebaseDatabase db = null;
public FirebaseDatabase getDb() {
if (db == null)
initializeFirebase();
return db;
}
protected void initializeFirebase() {
db = FirebaseDatabase.getInstance();
}
}
package de.scrum_master.Whosebug
import spock.lang.Specification
class FirebaseUtilitySpec extends Specification {
def "instantiating FirebaseUtility runs initialization code exactly once"() {
given:
FirebaseUtility f = Spy()
when:
f.getDb()
then:
1 * f.initializeFirebase()
when:
f.getDb()
then:
0 * f.initializeFirebase()
}
}
我有一个 Firebase 管理助手 class,我正在使用 Spock 进行测试。这个 class 的构造函数会在必要时调用 class 中的另一个方法来初始化某些字段,如下所示:
public class FirebaseUtility {
private static FirebaseDatabase db = null;
public FirebaseUtility() throws IOException {
if (db == null) {
initializeFirebase();
}
}
public void initializeFirebase() throws IOException {
InputStream serviceAccount = ClassLoader.getSystemResourceAsStream("serviceAccount.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("<my_database_url>").build();
FirebaseApp.initializeApp(options);
db = FirebaseDatabase.getInstance();
}
}
基本上,如果已经设置了 FirebaseDatabase,则执行所有初始化代码是没有意义的。
我试过这样做,但似乎不起作用:
class FirebaseUtilitySpec extends Specification {
def "instantiating FirebaseUtility should run initialization code"() {
given:
def f
when:
f = new FirebaseUtility()
then:
1 * f.initializeFirebase()
}
}
首先,您无法检查原始对象的交互,您需要使用模拟或间谍。此外,这些类型的对象无法拦截静态方法或构造函数上的交互。为此,您必须将 Mockito 甚至 PowerMock 添加到组合中。但基本上,静态方法无论如何都是丑陋的,并且没有必要在构造函数调用中初始化静态成员。只需对数据库对象使用惰性 getter 并拦截其行为。
我稍微简化了您的示例,删除了外部依赖项并仅模拟 Firebase,以便更容易回答 MCVE:
package de.scrum_master.Whosebug;
public class FirebaseDatabase {
private static FirebaseDatabase instance;
public static FirebaseDatabase getInstance() {
if (instance == null)
instance = new FirebaseDatabase();
return instance;
}
}
package de.scrum_master.Whosebug;
public class FirebaseUtility {
private static FirebaseDatabase db = null;
public FirebaseDatabase getDb() {
if (db == null)
initializeFirebase();
return db;
}
protected void initializeFirebase() {
db = FirebaseDatabase.getInstance();
}
}
package de.scrum_master.Whosebug
import spock.lang.Specification
class FirebaseUtilitySpec extends Specification {
def "instantiating FirebaseUtility runs initialization code exactly once"() {
given:
FirebaseUtility f = Spy()
when:
f.getDb()
then:
1 * f.initializeFirebase()
when:
f.getDb()
then:
0 * f.initializeFirebase()
}
}