fbi*_*jec 26 java junit unit-testing mocking mockito
我需要测试一些遗留代码,它在方法调用中使用单例.测试的目的是确保clas sunder测试调用单例方法.我在SO上看到过类似的问题,但是所有的答案都需要其他依赖项(不同的测试框架) - 我很遗憾只能使用Mockito和JUnit,但这种流行的框架应该是完全可能的.
单身人士:
public class FormatterService {
private static FormatterService INSTANCE;
private FormatterService() {
}
public static FormatterService getInstance() {
if (INSTANCE == null) {
INSTANCE = new FormatterService();
}
return INSTANCE;
}
public String formatTachoIcon() {
return "URL";
}
}
Run Code Online (Sandbox Code Playgroud)
被测试的课程:
public class DriverSnapshotHandler {
public String getImageURL() {
return FormatterService.getInstance().formatTachoIcon();
}
}
Run Code Online (Sandbox Code Playgroud)
单元测试:
public class TestDriverSnapshotHandler {
private FormatterService formatter;
@Before
public void setUp() {
formatter = mock(FormatterService.class);
when(FormatterService.getInstance()).thenReturn(formatter);
when(formatter.formatTachoIcon()).thenReturn("MockedURL");
}
@Test
public void testFormatterServiceIsCalled() {
DriverSnapshotHandler handler = new DriverSnapshotHandler();
handler.getImageURL();
verify(formatter, atLeastOnce()).formatTachoIcon();
}
}
Run Code Online (Sandbox Code Playgroud)
我们的想法是配置可怕的单例的预期行为,因为被测试的类将调用它的getInstance然后调用formatTachoIcon方法.不幸的是,这失败并显示错误消息:
when() requires an argument which has to be 'a method call on a mock'.
Run Code Online (Sandbox Code Playgroud)
nos*_*ame 27
您要求的是不可能的,因为您的遗留代码依赖于静态方法getInstance()而Mockito不允许模拟静态方法,因此以下行不起作用
when(FormatterService.getInstance()).thenReturn(formatter);
Run Code Online (Sandbox Code Playgroud)
有两种解决此问题的方法:
使用允许模拟静态方法的其他模拟工具(如PowerMock).
重构您的代码,以便您不依赖静态方法.我能想到的最少侵入性的方法是通过添加一个构造函数来DriverSnapshotHandler注入FormatterService依赖项.此构造函数将仅用于测试,您的生产代码将继续使用真正的单例实例.
public static class DriverSnapshotHandler {
private final FormatterService formatter;
//used in production code
public DriverSnapshotHandler() {
this(FormatterService.getInstance());
}
//used for tests
DriverSnapshotHandler(FormatterService formatter) {
this.formatter = formatter;
}
public String getImageURL() {
return formatter.formatTachoIcon();
}
}
Run Code Online (Sandbox Code Playgroud)然后,您的测试应如下所示:
FormatterService formatter = mock(FormatterService.class);
when(formatter.formatTachoIcon()).thenReturn("MockedURL");
DriverSnapshotHandler handler = new DriverSnapshotHandler(formatter);
handler.getImageURL();
verify(formatter, atLeastOnce()).formatTachoIcon();
Run Code Online (Sandbox Code Playgroud)
小智 16
我认为这是可能的.查看如何测试单例的示例
测试前:
@Before
public void setUp() {
formatter = mock(FormatterService.class);
setMock(formatter);
when(formatter.formatTachoIcon()).thenReturn(MOCKED_URL);
}
private void setMock(FormatterService mock) {
try {
Field instance = FormatterService.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(instance, mock);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Run Code Online (Sandbox Code Playgroud)
测试后 - 清理类非常重要,因为其他测试将与模拟实例混淆.
@After
public void resetSingleton() throws Exception {
Field instance = FormatterService.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, null);
}
Run Code Online (Sandbox Code Playgroud)
考试:
@Test
public void testFormatterServiceIsCalled() {
DriverSnapshotHandler handler = new DriverSnapshotHandler();
String url = handler.getImageURL();
verify(formatter, atLeastOnce()).formatTachoIcon();
assertEquals(MOCKED_URL, url);
}
Run Code Online (Sandbox Code Playgroud)
我只想从 noscreenname 完成解决方案。解决方案是使用 PowerMockito。因为 PowerMockito 可以做类似 Mockito 的事情,所以有时你可以只使用 PowerMockito 。
示例代码在这里:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.lang.reflect.Field;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({Singleton.class})
public class SingletonTest {
@Test
public void test_1() {
// create a mock singleton and change
Singleton mock = mock(Singleton.class);
when(mock.dosth()).thenReturn("succeeded");
System.out.println(mock.dosth());
// insert that singleton into Singleton.getInstance()
PowerMockito.mockStatic(Singleton.class);
when(Singleton.getInstance()).thenReturn(mock);
System.out.println("result:" + Singleton.getInstance().dosth());
}
}
Run Code Online (Sandbox Code Playgroud)
单例类:
public class Singleton {
private static Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
public String dosth() {
return "failed";
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的摇篮:
/*
* version compatibility see: https://github.com/powermock/powermock/wiki/mockito
*
* */
def powermock='2.0.2'
def mockito='2.8.9'
...
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
/** mock **/
testCompile group: 'org.mockito', name: 'mockito-core', version: "${mockito}"
testCompile "org.powermock:powermock-core:${powermock}"
testCompile "org.powermock:powermock-module-junit4:${powermock}"
testCompile "org.powermock:powermock-api-mockito2:${powermock}"
/**End of power mock **/
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
34568 次 |
| 最近记录: |