mockito 模拟/PowerMock:如何在SUT中重置模拟静态变量?

qco9c6ql  于 2022-11-08  发布在  其他
关注(0)|答案(3)|浏览(330)

我讨厌将单元测试引入遗留代码库,但我不得不这样做。
到目前为止,我使用Mockito和PowerMock成功地将单元测试引入到遗留代码库中,一直运行得很好,直到我遇到了这样的情况:
在SUT中,有几个静态变量(我在PowerMock的帮助下模拟了这些变量,模拟了静态方法和构造函数)。
现在,在第一种测试方法中,所有测试都运行良好,模拟的静态var返回预期的输出值。
但在随后的测试方法中,模拟的静态对象总是返回在第一次测试中设置的值,尽管我在测试之前对它调用了reset()。

// legacy code base:
public class SUT {
  private static Collaborator1 c1 = null;
  private static Collaborator2 c2 = null;

  public SUT(param1) {
    if (c1 == null) {
        c1 = Collaborator1.instance(param1);
        c2 = new Collaborator2(c1);
    } else {
    }
  }
}

// newly introduced unit tests:
@RunWith(PowerMockRunner.class)
@PrepareForTest({
    SUT.class,                  // to mock: new Collaborator2(..), as required by PowerMock when mocking constructors
    Collaborator1.class,        // to mock: Collaborator1.instance(..), as required by PowerMock in mocking static methods
})
public class SUTTest {

  private SUT sut;

  private Collaborator1 c1 = mock(Collaborator1.class);
  private Collaborator2 c2 = mock(Collaborator2.class);

  @Before  
  public void setup() {
    // mock c1:
    PowerMockito.mockStatic(Collaborator1.class);
    when(Collaborator1.instance(param1)).thenReturn(c1);

    // mock c2:
    PowerMockito.whenNew(Collaborator2.class).withArguments(c1).thenReturn(c2);

    reset(c1);
    reset(c2);

    sut = new SUT(param1);
  }

  @Test
  public void test1() {
    when(c2.foo(input1)).thenReturn(out1); 

    // do something
  }

  @Test
  public void test2() {
    when(c2.foo(input2)).thenReturn(out2);    // BANG!!! c2.foo(input2) always return "out1"

    // do something
  }
}

由于SUT的构造函数只在静态c1为空时示例化c1和c2,因此它们(c1,c2)在子序列调用中不会被重新示例化。我不明白的是为什么reset(c1),reset(c2)在test2中没有作用?
你知道吗?

hc2pp10m

hc2pp10m1#

基本上,我不能在两个不同的测试运行中设置stub(模拟的静态示例变量)。我必须在第一个@Before中设置预期的行为。
所以我们不用

@Before  
  public void setup() {
    ...
  }

  @Test
  public void test1() {
    when(c2.foo(input1)).thenReturn(out1); 
  }

  @Test
  public void test2() {
    when(c2.foo(input2)).thenReturn(out2); 
  }

我应该使用以下序列:

@Before  
  public void setup() {
    when(c2.foo(input1)).thenReturn(out1); 
    when(c2.foo(input2)).thenReturn(out2);
  }

  @Test
  public void test1() {
    // do something
  }

  @Test
  public void test2() {
    // do something
  }

PowerMock/Mockito中是否存在某些限制(bug?)?

wpcxdonn

wpcxdonn2#

尝试将静态mock设置移到@BeforeClass设置方法中,但将reset(mocks)调用留在test setup()方法中。您希望只设置mockStatic一次,但由于它们是静态的,因此您需要在每次测试时重置它们,否则它们会与后续测试混淆。
即尝试

@BeforeClass  
public void setupClass() {
    // mock c1:
    PowerMockito.mockStatic(Collaborator1.class);
    when(Collaborator1.instance(param1)).thenReturn(c1);

    // mock c2:
    PowerMockito.whenNew(Collaborator2.class).withArguments(c1).thenReturn(c2);
}

@Before  
public void setup() {
  reset(c1);
  reset(c2);

  sut = new SUT(param1);
}

@Test
public void test1() {
  // do something
}

...

aiazj4mn

aiazj4mn3#

如果您使用Mockito来模拟静态方法,则需要
1.在try范围内创建静态模拟(try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) {
1.如果您在try范围之外创建了静态模拟,请在测试后关闭静态模拟(utilities.close()

相关问题