如何模拟依赖于输入值的依赖项?

huangapple go评论62阅读模式
英文:

How to mock dependencies that depend on input value?

问题

我想对这样一个方法进行单元测试:

public String handleRequest(Event event) {
    for(Message msg : event.getRecords()){
        SDKClient client = new SDKClient(msg.getUser(), msg.getPassword());
        String output = client.makeAPICall();
        return output.toUpperCase();
    }
}

通常情况下,我们会通过将依赖项(如 SDKClient)作为参数传递,并在 Junit/Mockito 中进行模拟。但是,在这种情况下,我不能简单地传递它,因为 SDKClient 依赖于传入的实际事件。而且,每个事件中的每条消息都需要一个单独的客户端,数量不确定。我想将整个方法作为一个单元进行测试,但我事先不知道依赖关系。这种情况是否有可能?

英文:

I want to unit-test a method like this:

public String handleRequest(Event event) {
      for(Message msg : event.getRecords()){
           SDKClient client = new SDKClient(msg.getUser(), msg.getPassword());
           String output = client.makeAPICall();
           return output.toUpperCase();
       }
   }

}

Typically, we mock dependencies like SDKClient by passing them in as arguments and mocking them in Junit/Mockito. However, in this case, I cannot just pass it because the SDKClient depends on the actual events passed in. There is also an undetermined number of clients, one for each message in the event. I want to unit test the method as a whole, but I do not know the dependencies in advance. Is it possible?

答案1

得分: 1

在这种情况下,您传入的是一种抽象new SDKClient调用的函数:

interface SdkClientProvider {
    SDKClient(String user, String password);
}

在这种特定情况下,您可以使用BiFunction<String, String, SDKClient>

由于new SDKClient很可能是这个类唯一的“活”实现,您甚至可以这样做:

class MyService {
    @Setter
    private BiFunction<String, String, SDKClient> createClient = SDKClient::new;

    ...
}

在依赖于系统java.time.Clock的情况下,经常看到这种模式。

(请注意,“创建、使用和处理服务对象”是一个非常值得质疑的设计,除非您被迫使用一些设计不良的外部库,否则最好进行重构。)

英文:

In that case, what you pass in is some kind of function that abstracts the new SDKClient call:

interface SdkClientProvider {
    SDKClient(String user, String password);
}

In this particular case, you could use BiFunction&lt;String, String, SDKClient&gt; if you prefer.

As new SDKClient is likely to be the only "live" implementation of this class, you can even do something like this:

class MyService {
    @Setter
    private BiFunction&lt;String, String, SDKClient&gt; createClient = SDKClient::new;

    ...
}

This pattern is commonly seen when depending on the system java.time.Clock.

(Note that the "create, use, and dispose of a service object" is a very questionable design, and unless you're stuck with consuming some badly-designed external library, it's begging for refactoring.)

huangapple
  • 本文由 发表于 2020年10月11日 10:42:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/64300146.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定