如何破坏静态物体? - 测试静态字段时出现问题

时间:2016-03-11 12:08:13

标签: java testing junit static

我想测试这个类,并且不想将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 
}

2 个答案:

答案 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++;
    }
}