我想测试这个类,并且不想将id设置为public或允许它从外部设置它。
public class A {
private int id;
private static int prevId = 0;
private static nextId(){
prevId++;
}
public A(){
id = nextId()
}
public int getId(){
return id;
}
...
}
如果我测试它并在设置中生成A的对象:
A foo;
@Before
public void setUp(){
foo = new A();
}
@Test
public void test1(){
assertEquals(1, foo.getId());
}
@Test
public void test2(){
assertEquals(1, foo.getId());
}
测试失败,因为setUp被调用两次因此 静态字段 id 是2
断言失败不等于 预期1 实际2
如上所述我不想拥有公共访问修饰符的id, 否则我可以把它设置为0。
有没有办法销毁静态对象 拆除方法?
@After
public void tearDown(){
//TODO finalize static object A
}
答案 0 :(得分:4)
非常简单 - 如果不提供重置prevId
值的方法,则不能。可测试性降低是反对可变全局状态的(许多)论据之一。
您可以提供工厂类来创建A
个实例,而不是像这样依赖可变的全局状态:
class AFactory {
private int nextId;
A createA() {
return new A(nextId++);
}
}
您需要在当前需要创建AFactory
实例的任何位置注入A
的单个实例。现在,在测试中,您只需为每个测试用例创建一个新的AFactory
,每次nextId
值都将从零开始。
或者,您可以通过创建某种唯一值提供程序类来反转控制:
final class UniqueValueProvider {
private int nextId;
int nextId() {
return nextId++;
}
}
然后将其设为A
的构造函数的参数:
class A {
final int id;
A(UniqueValueProvider uvp) {
this.id = uvp.nextId();
}
}
如果你想任意地继承A
:
class ChildOfA extends A {
ChildOfA(UniqueValueProvider uvp) {
super(uvp);
}
}
同样,在您的测试中,您只需创建UniqueValueProvider
的新实例;你需要在任何地方注入一个你需要创建A
(或其中一个子类)的实例。
作为旁注:你也可以改变你正在测试的东西。您可以创建两个实例,并断言ID与另一个不同/ 1等,而不是断言每次ID为1;
Foo first = new Foo();
Foo second = new Foo();
assertNotEqual(first.getId(), second.getId());
答案 1 :(得分:1)
如果它只是您所描述的测试场景,只需使用反射来重置@Before
方法中静态成员变量的值。如果你正在使用Mockito,你可以使用他们的Whitebox
助手来实现这一点,如下所示:
import org.mockito.internal.util.reflection.Whitebox;
Foo foo = new Foo();
@Before
public void setup() {
Whitebox.setInternalState(foo, "STATIC_MEMBER", 0);
}
@Test
public void staticMemberTest() {
assertEquals(0, foo.next());
assertEquals(1, foo.next());
}
@Test
public void anotherStaticMemberTest() {
assertEquals(0, foo.next());
assertEquals(1, foo.next());
}
private static class Foo {
private static int STATIC_MEMBER = 0;
public int next() {
return STATIC_MEMBER++;
}
}