如何在超级构造函数中测试 object 初始化?

How to test object initialisation within a super constructor?

我有一个 BasePersister,它使用 Dagger 在其构造函数中构建了一个复杂的持久性客户端:

public abstract class BasePersister {
   @Getter
   private PersistenceClient client;

   public BasePersister() {
      this.client = DaggerPersistenceClientComponent.create().getClient();
   }

   public abstract void persist(String data);

   protected void helper() {
      System.out.println("I am a helper");
   }
}

想法是 child 持久化器 classes 可以扩展基础 class 并与客户端一起执行其持久化逻辑。一个例子 child class:

public class SpecialPersister extends BasePersister {
   public void persist(String data) {
      // do stuff with the client
      getClient().persist(data);
      // use the shared helper
      helper();
   }
}

在基础 class 构造函数中移动客户端实例化是理想的,因为在我的 PersisterFactory 中,我可以简单地调用像 new SpecialPersister() 这样的语句;构造函数不接受任何参数,不需要 Dagger 来实例化并且工厂完全不知道任何客户端。

我在测试这些 child classes 时遇到问题,我怀疑这与我在基本构造函数中秘密实例化客户端的设计选择有关。

更具体地说,在我的 SpecialPersisterTest class 中,我无法执行 Spy(SpecialPersister),因为这会调用基本构造函数,然后实例化我的复杂客户端(给我一个错误) .我需要以某种方式模拟此 super-constructor 调用,以便它实际上不会调用具有复杂网络调用等的客户端实例化

理想情况下,我可以做一个简单的测试,例如检查:

def "my ideal test"() {
   given:
      specialPersister.persist(validData)
   then:
      1 * specialPersister.getClient()
   and:
      1 * specialPersister.helper()
}

Moving the client instantiation within the base class constructor was ideal because in my PersisterFactory, I can simply invoke statements like new SpecialPersister(); the constructor doesn't take any arguments, doesn't need Dagger to instantiate and the factory is completely unaware of any clients.

I'm having trouble testing these child classes and I'm suspecting it has to do with my design choice of secretly instantiating clients within the base constructors.

这个设计选择就是问题所在。如果您希望代码在不调用真实客户端的情况下可测试,您将需要能够对您的客户端进行存根。一种选择是在实例化时传递 PersistenceClient

由于您使用的是工厂模式,因此您的工厂可以提供它而无需担心代码中其他地方的细节。它应该知道如何创建 Persister 对象,无论它是否需要了解有关客户端的详细信息 - 应该鼓励在这个级别进行耦合。您可能还希望您的工厂也接受争论,以便可以测试工厂的 Persister。

public abstract class BasePersister {
    private PersistenceClient client;
    public BasePersister(PersistenceClient client) {
        this.client = client;
    }
}
public class SpecialPersister extends BasePersister {
    public SpecialPersister(PersistenceClient client) {
        super(client);
    }
}

public class PersisterFactory {
    // pass in the client once to a PersisterFactory instance
    private PersistenceClient client;
    public PersisterFactory(PersistenceClient client) {
        this.client = client;
    }
    public SpecialPersister createSpecialPersister() {
        return new SpecialPersister(client);
    }
}

// elsewhere
PersisterFactory persisterFactory = new PersisterFactory(DaggerPersistenceClientComponent.create().getClient());
// ...
BasePersister persister = persisterFactory.createSpecialPersister();