2011-04-26 55 views
4

我讨厌将单元测试引入遗留代码库,但我不得不这样做。
直到现在,我成功地使用Mockito和PowerMock将单元测试引入了遗留代码库。工作得很好,直到我遇到了这样的情况:

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

在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中没有效果?

任何想法?

+0

你试过手动复位C1在@After方法使用反射空? – alpian 2011-04-26 07:06:19

+0

我试着在@Before方法中将c1重置为null,应该具有相同的效果?无论如何,我会尝试@After。顺便说一句,在介绍Mockito和PowerMock之后,我的测试表现变得极其糟糕。一个简单的测试需要10分钟以上。 – Tumer 2011-04-26 07:38:59

+0

@alpian:@After没有运气,我试着在@After方法中重置c1,c2和sut为null。但是从调试会话中,我发现在test2之前,在SUT的构造函数中,c1仍然不为null。 – Tumer 2011-04-26 08:11:58

回答

4

终于搞定了。基本上,我不能在两个不同的测试运行中设置存根(模拟的静态实例变量)。我必须在第一个@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); 
    } 

我应该用这个顺序:在PowerMock/

的Mockito
@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 
    } 

一些限制(错误?)?

0

尝试将静态模拟设置移动到@BeforeClass设置方法,但在您的测试setup()方法中保留重置(mocks)调用。你只需要设置你的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 
} 

...