Jukito/Mockito 用静态方法测试

Jukito/Mockito Test with static method

我正在尝试测试一个 class(使用 Jukito 和 Mockito),不幸的是它扩展了另一个 class,它有一个静态方法调用。是否有可能以某种方式跳过这个电话?我宁愿不使用 PowerMockito。

public class A extends B {

    @Inject
    public A(final String s){
        super(s);
    }
}

public abstract class B {

    private String s;

    protected String m = C.get().createUniqueId(); //Exception is thrown here

    public B(String s){
        this.s = s;
    }
}

public class C {
    private static C c; //assume this is never null

    public static C get() {
        return c;
    }   

    public final native String createUniqueId() {}

}

@RunWith(JukitoRunner.class)
public class ATest {

    @Inject 
    A a;

    @Test
    public void onMethod1Test(){
    }
}

当运行 ATest时,我得到以下错误:

Error injecting constructor, java.lang.UnsatisfiedLinkError: C

我以为是因为静态方法,我错了吗?

请注意,所有 classes 只是我真实 classes 中的示例,C class 不是我编写的,无法更改(不幸的是)。但是我的 classes 背后的想法和这些是一样的,我只是改了名字,只留下了相关的部分。

朱基托 claims:

The combined power of JUnit, Guice and Mockito.

但问题是:none 这些产品允许您 mock 静态方法。

唯一能够做到这一点的框架:PowerMock(ito) 和 JMockit。

正如您已经解释过的:通常您会 "bypass" 这个 "deficiency" 通过简单地编写 可测试 代码(避免静态调用)。但是由于您无法改进您的设计,您只有这两个选择:使用 PowerMock(ito) 测试此 class - 或不测试它。

所以目标是使用 CB 的任何新实例上生成 m。您无法控制 C,您正试图弄清楚如何测试它,对吗?我想你必须选择你的毒药,但我可以根据你的情况想出另一种选择 "poison"。

您在 B 上添加一个静态字段并为其提供更多访问权限,否则将是合适的:

public abstract class B {
   static C c = C.get();
   private String s;
   protected String m = c.createUniqueId();
   public B(String s){
     this.s = s;
   }
}

现在您可以将 B.c 重新分配给测试中的模拟实例。我更熟悉 JUnit 和 Spock,所以我会尝试让您弄清楚其中的机制。由于单元测试与它们正在测试的 class 在同一个包中,因此您可以使用包私有范围。如果 AB 在不同的包中,则您必须将其提升为 protected。这既快速又简单,但会使您面临其他代码重新分配的可能性 B.c。您必须根据根本不测试 A 的风险来判断这种风险。

您还可以考虑添加 classes 和接口以从 AB 中完全隐藏 C。本质上,你创建了类似 BFactory 的东西,它有 Supplier<String> 来生成 m。在单元测试中,您模拟供应商,在生产中,您使用基于 C 的实现。我能想到的每一种方法都是混乱的,或者不会强制 B 的每个子 class 以相同的方式生成 m。唯一的例外是使用组合并将 B 的实例放在 A 上实际上更有意义。那么你可能有一个不错的方法来做到这一点。