問題描述
我需要測(cè)試一些在方法調(diào)用中使用單例的遺留代碼.測(cè)試的目的是確保類 sunder 測(cè)試調(diào)用單例方法.我在 SO 上看到過類似的問題,但所有答案都需要其他依賴項(xiàng)(不同的測(cè)試框架)——不幸的是,我僅限于使用 Mockito 和 JUnit,但使用這種流行的框架應(yīng)該是完全可能的.
I need to test some legacy code, which uses a singleton in a a method call. The purpose of the test is to ensure that the clas sunder test makes a call to singletons method. I have seen similar questions on SO, but all the answers require other dependencies (different test frameworks) - I'm unfortunately limited to using Mockito and JUnit, but this should be perfectly possible with such popular framework.
單身人士:
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";
}
}
被測(cè)類:
public class DriverSnapshotHandler {
public String getImageURL() {
return FormatterService.getInstance().formatTachoIcon();
}
}
單元測(cè)試:
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();
}
}
這個(gè)想法是配置可怕的單例的預(yù)期行為,因?yàn)楸粶y(cè)試的類將調(diào)用它的 getInstance 和 formatTachoIcon 方法.不幸的是,這失敗并顯示錯(cuò)誤消息:
The idea was to configure the expected behaviour of the dreaded singleton, since the class under test will call it's getInstance and then formatTachoIcon methods. Unfortunately this fails with an error message:
when() requires an argument which has to be 'a method call on a mock'.
推薦答案
你的問題是不可能的,因?yàn)槟愕倪z留代碼依賴于一個(gè)靜態(tài)方法 getInstance()
而 Mockito 不允許模擬靜態(tài)方法,所以下面這行不起作用
What you are asking is not possible because your legacy code relies on a static method getInstance()
and Mockito does not allow to mock static methods, so the following line won't work
when(FormatterService.getInstance()).thenReturn(formatter);
解決這個(gè)問題有兩種方法:
There are 2 ways around this problem:
使用允許模擬靜態(tài)方法的不同模擬工具,例如 PowerMock.
Use a different mocking tool, such as PowerMock, that allows to mock static methods.
重構(gòu)你的代碼,讓你不依賴靜態(tài)方法.我能想到的實(shí)現(xiàn)這一點(diǎn)的侵入性最小的方法是向 DriverSnapshotHandler
添加一個(gè)構(gòu)造函數(shù),該構(gòu)造函數(shù)注入一個(gè) FormatterService
依賴項(xiàng).此構(gòu)造函數(shù)將僅在測(cè)試中使用,您的生產(chǎn)代碼將繼續(xù)使用真正的單例實(shí)例.
Refactor your code, so that you don't rely on the static method. The least invasive way I can think of to achieve this is by adding a constructor to DriverSnapshotHandler
that injects a FormatterService
dependency. This constructor will be only used in tests and you production code will continue to use the real singleton instance.
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();
}
}
那么,你的測(cè)試應(yīng)該是這樣的:
Then, your test should look like this :
FormatterService formatter = mock(FormatterService.class);
when(formatter.formatTachoIcon()).thenReturn("MockedURL");
DriverSnapshotHandler handler = new DriverSnapshotHandler(formatter);
handler.getImageURL();
verify(formatter, atLeastOnce()).formatTachoIcon();
這篇關(guān)于用 mockito 模擬單例的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!