用Mockitotesting一个新的()调用

我有一个遗留类,其中包含一个new()调用来实例化一个LoginContext():

public class TestedClass { public LoginContext login(String user, String password) { LoginContext lc = new LoginContext("login", callbackHandler); } } 

我想用Mockito来testing这个类来模拟LoginContext,因为它需要在实例化之前设置JAAS安全性的东西,但是我不确定如何在不改变login()方法来外部化LoginContext的情况下如何做到这一点。 是否有可能使用Mockito模拟LoginContext类?

为了将来,我会推荐Eran Harel的答案(重新移植到可以被嘲笑的工厂)。 但是,如果你不想改变原始的源代码,使用非常方便和独特的function: 间谍 。 从文档 :

你可以创build真实对象的间谍。 当你使用间谍,那么真正的方法被调用(除非方法被扼杀)。

真正的间谍应该谨慎地偶尔使用 ,例如在处理遗留代码时。

在你的情况下,你应该写:

 TestedClass tc = spy(new TestedClass()); LoginContext lcMock = mock(LoginContext.class); when(tc.login(anyString(), anyString())).thenReturn(lcMock); 

我完全赞成Eran Harel的解决scheme,在不可能的情况下,Tomasz Nurkiewicz对间谍的build议非常好。 但是,值得注意的是,有些情况下都不适用。 例如,如果login方法有点“更强大”:

 public class TestedClass { public LoginContext login(String user, String password) { LoginContext lc = new LoginContext("login", callbackHandler); lc.doThis(); lc.doThat(); } } 

…这是旧的代码,无法重构提取初始化一个新的LoginContext到自己的方法,并应用上述解决scheme之一。

为了完整起见,值得一提的是第三种技术 – 使用PowerMock在new操作符被调用时注入模拟对象。 PowerMock不是一个银弹,但。 它的工作原理是对其模拟的类进行字节码操作,如果被testing的类使用字节码操作或reflection,并且至less从我的个人经验来看,这可能会是一个狡猾的做法。 再次,如果没有其他的select,唯一的select必须是好的select:

 @RunWith(PowerMockRunner.class) @PrepareForTest(TestedClass.class) public class TestedClassTest { @Test public void testLogin() { LoginContext lcMock = mock(LoginContext.class); whenNew(LoginContext.class).withArguments(anyString(), anyString()).thenReturn(lcMock); TestedClass tc = new TestedClass(); tc.login ("something", "something else"); // test the login's logic } } 

您可以使用工厂来创buildlogin上下文。 然后,你可以嘲笑工厂,并返回你想要的testing。

 public class TestedClass { private final LoginContextFactory loginContextFactory; public TestedClass(final LoginContextFactory loginContextFactory) { this.loginContextFactory = loginContextFactory; } public LoginContext login(String user, String password) { LoginContext lc = loginContextFactory.createLoginContext(); } } public interface LoginContextFactory { public LoginContext createLoginContext(); } 

不是我所知道的,但是当你创build一个你想testing的TestedClass的实例时,如何做这样的事情呢?

 TestedClass toTest = new TestedClass() { public LoginContext login(String user, String password) { //return mocked LoginContext } }; 

另一个select是使用Mockito创build一个TestedClass的实例,让模拟的实例返回一个LoginContext。

  public class TestedClass { public LoginContext login(String user, String password) { LoginContext lc = new LoginContext("login", callbackHandler); lc.doThis(); lc.doThat(); } } 

– testing等级:

  @RunWith(PowerMockRunner.class) @PrepareForTest(TestedClass.class) public class TestedClassTest { @Test public void testLogin() { LoginContext lcMock = mock(LoginContext.class); whenNew(LoginContext.class).withArguments(anyString(), anyString()).thenReturn(lcMock); //comment: this is giving mock object ( lcMock ) TestedClass tc = new TestedClass(); tc.login ("something", "something else"); /// testing this method. // test the login's logic } } 

当调用实际的方法tc.login ("something", "something else"); 从testLogin(){ – 这个LoginContext lc被设置为null,并在调用lc.doThis();抛出NPE lc.doThis();