2014-03-13 100 views
2

我遇到了mockito.spy方法的麻烦。Mockito间谍方法不起作用

我最近刚到一个“老”的项目,我的首要任务是增加它的Mockito,而要做到真正的单元测试:)

项目有这里的许多观念问题,但它不是点;)

我解释我的问题:

我有一个类

public class Tutu{ 
    public Tutu(){ 
    } 
} 

public class Toto{ 
    public Toto(){ 
    } 
    public int executeToto(Tutu tutu){ 
    //do some stuff 
    return 5; 
    } 
} 

public class Titi{ 
    private Toto toto; 

    public Titi(){ 
    this.toto = new Toto();  
    } 

    public void executeTiti(){ 
     //do some stuff 
     Tutu tutu = new Tutu(); 
     int ret = this.toto.executeToto(tutu); 
     //do some stuff 
    } 
} 

在我的测试类TitiTest.java我只需要测试executeTiti,我不想测试executeToto的东西,因为这个类有自己的测试类TotoTest.java。

但你可以看到,TOTO是实例化蒂蒂构造,所以我尝试这样: (我使用PowerMock在我的测试过,所以我用PowerMockRunner,但它似乎并没有成为问题)

@RunWith(PowerMockRunner.class) 
public class TitiTest { 

@Test 
public void testExecuteTiti(){ 
    Toto toto = Mockito.spy(new Toto()); 
    Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class)); 

    Titi testedObject = new Titi(); 
    testedObject.executeTiti(); 
} 
} 

但真正的方法始终在呼唤和RET = 5,每次:(

难道我错过了什么?我看了很多帖子这个对计算器,并尝试所有的解决方案,但它从来没有工作,因为我认为我在做正确的事

我用junit4.11/powermock1.5.4/mockito1.9.5

回答

7
Toto toto = Mockito.spy(new Toto()); 

记住,这个间谍/你在这行创建托托的实例,而不是每一个新创建的托托存根。所以,当你拨打:

Titi testedObject = new Titi(); 
testedObject.executeTiti(); 

构造new Titi()本身产生托托,通过影响的Mockito的新实例,所以this.toto.executeAction()该调用总是返回5.


因为你与运行PowerMockito,你有stubbing Toto's constructor的选项:我最喜欢的是创建一个二次CONSTRU

@RunWith(PowerMockRunner.class) 
@PrepareForTest(Titi.class) // stub the calling class Titi, not Toto! 
public class TitiTest { 
    @Test public void testExecuteTiti() { 
    Toto toto = Mockito.spy(new Toto()); 
    Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class)); 

    PowerMockito.whenNew(Toto.class).withAnyArguments().thenReturn(toto); 

    Titi testedObject = new Titi(); 
    testedObject.executeTiti(); 
    } 
} 

但选项构造函数用于蒂蒂,来进行测试:

public Titi(){ 
    this.toto = new Toto();  
} 

/** For testing only. Uses the passed Toto instance instead of a new one. */ 
Titi(Toto toto){ 
    this.toto = toto; 
} 

,然后只需要你调整你的测试是这样的:

@Test public void testExecuteTiti(){ 
    Toto toto = Mockito.spy(new Toto()); 
    Mockito.doReturn(2).when(toto).executeToto(Mockito.any(Tutu.class)); 

    Titi testedObject = new Titi(toto); 
    testedObject.executeTiti(); 
} 
+0

你好,谢谢你的帮助,发表我的问题后,我终于改变了构造函数来传递好的实例及其工作。我只想知道是否有另一个解决方案,因为它是遗留代码,没有测试,我不想触摸现有的代码,但即时通讯同意你,我在这种情况下没有选择:)谢谢 –

+0

我觉得遗留代码的快速重构很容易使测试更好,但您可以在答案中追求PowerMockito解决方案,而无需更改任何生产代码。您可能需要调整PowerMockito代码;我的经验是有限的。祝你好运! –

0

你似乎什么是失踪的事实是,你的间谍对托托类从来没有真正被Titi类使用过。

我会做你的情况是

1)重新构建蒂蒂类接受托托作为构造的依赖。这样,你可以很容易地与任何托托创建蒂蒂(也有在你的单元测试使用模拟)

2)如果选项1是出了问题,你可以做到以下几点:

public class Titi{ 
    private Toto toto; 

    public Titi(){ 
    this.toto = new Toto();  
    } 

    public void executeTiti(){ 
     //do some stuff 
     Tutu tutu = new Tutu(); 
     int ret = getToto().executeToto(tutu); 
     //do some stuff 
    } 

    //package private - used for overriding via spying 
    Toto getToto() { 
     return toto; 
    } 
} 

@RunWith(MockitoJUnitRunner.class) 
public class TitiTest { 

@Test 
public void testExecuteTiti(){ 
    Toto toto = Mockito.mock(Toto.class); 
    when(toto.executeToto(Mockito.any(Tutu.class)).thenReturn(2); 

    Titi testedObject = new Titi(); 
    testedObject = spy(testedObject); 
    doReturn(toto).when(testedObject).getToto(); 

    testedObject.executeTiti(); 
} 
} 
+0

是的,就像我在前面的回答中所说的,我没有选择更改构造函数。也感谢你的帮助:) –