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 - 或不测试它。
所以目标是使用 C
在 B
的任何新实例上生成 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 在同一个包中,因此您可以使用包私有范围。如果 A
与 B
在不同的包中,则您必须将其提升为 protected
。这既快速又简单,但会使您面临其他代码重新分配的可能性 B.c
。您必须根据根本不测试 A
的风险来判断这种风险。
您还可以考虑添加 classes 和接口以从 A
和 B
中完全隐藏 C
。本质上,你创建了类似 BFactory
的东西,它有 Supplier<String>
来生成 m
。在单元测试中,您模拟供应商,在生产中,您使用基于 C
的实现。我能想到的每一种方法都是混乱的,或者不会强制 B
的每个子 class 以相同的方式生成 m
。唯一的例外是使用组合并将 B
的实例放在 A
上实际上更有意义。那么你可能有一个不错的方法来做到这一点。
我正在尝试测试一个 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 - 或不测试它。
所以目标是使用 C
在 B
的任何新实例上生成 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 在同一个包中,因此您可以使用包私有范围。如果 A
与 B
在不同的包中,则您必须将其提升为 protected
。这既快速又简单,但会使您面临其他代码重新分配的可能性 B.c
。您必须根据根本不测试 A
的风险来判断这种风险。
您还可以考虑添加 classes 和接口以从 A
和 B
中完全隐藏 C
。本质上,你创建了类似 BFactory
的东西,它有 Supplier<String>
来生成 m
。在单元测试中,您模拟供应商,在生产中,您使用基于 C
的实现。我能想到的每一种方法都是混乱的,或者不会强制 B
的每个子 class 以相同的方式生成 m
。唯一的例外是使用组合并将 B
的实例放在 A
上实际上更有意义。那么你可能有一个不错的方法来做到这一点。