2017-07-28 108 views
1

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

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

我以为这是因为一个静态方法的,是我错了吗?

请注意,所有的类都只是我真正的类的例子,C类不是我写的,不能更改(不幸的是)。但是我的课程背后的想法是一样的,我只是改了名字,只留下了相关的部分。

回答

1

Jukito claims

The combined power of JUnit, Guice and Mockito.

不过的事情是:没有这些产品可以让你模拟静态方法。

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

正如您已经解释过的那样:通常只需编写可测试代码(即避免静态调用)即可“绕过”这个“缺陷”。但是,由于无法改进设计,因此只有以下两种选择:使用PowerMock(ito)来测试此类 - 或者不对其进行测试。

+0

即使我知道所有这些,我想我希望我错过了一些东西。由于我不太喜欢使用PowerMockito并且不能重写C类,因此此时我不会测试我的课程。我会接受你的答案,因为你花时间写一个简单的解释。 – CrazySabbath

0

因此,我们的目标是使用CB的任何新实例上生成m。你不控制C,你试图找出如何测试它,对吧?我认为你必须选择你的毒药,但我可以为你的情况考虑另一种“毒药”的选择。

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更加熟悉,所以我会试着弄清楚它的机制。由于单元测试与它们正在测试的类位于同一个包中,因此可以使用包私有范围。如果AB不在一个包中,那么您必须将其升级至protected。这很快且容易,但是让您可以重新分配其他代码B.c。您必须判断该风险是否根本不会测试A

您也可以考虑添加类和接口以从AB中完全隐藏C。从本质上讲,你可以创建类似BFactory的产品,其中包含Supplier<String>以生成m。在单元测试中,你嘲笑供应商,在生产中使用基于C的实现。我所能想到的任何方式都是混乱的,或者不会强制B的每个子类以相同的方式生成m。唯一的例外是,如果它实际上使用合成更有意义并且在A上放置B的实例。那么你可能有一个体面的方式来做到这一点。