bwo*_*nes 57 java junit unit-testing mockito
我有一个遗留类,其中包含一个new()调用来实例化LoginContext():
public class TestedClass {
public LoginContext login(String user, String password) {
LoginContext lc = new LoginContext("login", callbackHandler);
}
}
Run Code Online (Sandbox Code Playgroud)
我想使用Mockito测试这个类来模拟LoginContext,因为它要求在实例化之前设置JAAS安全性东西,但是我不知道如何在不更改login()方法来外化LoginContext的情况下这样做.是否可以使用Mockito来模拟LoginContext类?
Tom*_*icz 54
对于未来,我会推荐Eran Harel的答案(重构转移new到可以嘲笑的工厂).但是,如果您不想更改原始源代码,请使用非常方便且独特的功能:间谍.从文档:
您可以创建真实对象的间谍.当你使用spy时,会调用真正的方法(除非方法被存根).
应该谨慎使用真正的间谍,例如在处理遗留代码时.
在你的情况下你应该写:
TestedClass tc = spy(new TestedClass());
LoginContext lcMock = mock(LoginContext.class);
when(tc.login(anyString(), anyString())).thenReturn(lcMock);
Run Code Online (Sandbox Code Playgroud)
Mur*_*nik 33
我全都是Eran Harel的解决方案,在不可能的情况下,Tomasz Nurkiewicz对间谍的建议非常好.但是,值得注意的是,在某些情况下两者都不适用.例如,如果login方法有点"更强":
public class TestedClass {
public LoginContext login(String user, String password) {
LoginContext lc = new LoginContext("login", callbackHandler);
lc.doThis();
lc.doThat();
}
}
Run Code Online (Sandbox Code Playgroud)
...这是旧的代码,无法重构以提取新LoginContext的自己的方法的初始化并应用上述解决方案之一.
为了完整起见,值得一提的是第三种技术 - 在调用运算符时使用PowerMock注入模拟对象new.但是,PowerMock并不是一颗银弹.它的工作原理是对它所模拟的类应用字节码操作,如果测试类使用字节代码操作或反射,并且至少根据我的个人经验,已知可以为测试引入性能损失,这可能是狡猾的做法.然后,如果没有其他选项,唯一的选择必须是好的选择:
@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
}
}
Run Code Online (Sandbox Code Playgroud)
Era*_*rel 23
您可以使用工厂来创建登录上下文.然后你可以模拟工厂并返回你想要的任何测试.
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();
}
Run Code Online (Sandbox Code Playgroud)
小智 5
public class TestedClass {
public LoginContext login(String user, String password) {
LoginContext lc = new LoginContext("login", callbackHandler);
lc.doThis();
lc.doThat();
}
}
Run Code Online (Sandbox Code Playgroud)
-测试类别:
@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
}
}
Run Code Online (Sandbox Code Playgroud)
tc.login ("something", "something else");从testLogin()调用实际方法时,{-此LoginContext lc设置为null并在调用时抛出NPElc.doThis();