我需要测试一些遗留代码,它们在一个方法调用中使用了单例。测试的目的是确保类分离测试调用单例方法。我在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";
}
}
受测类:
public class DriverSnapshotHandler {
public String getImageURL() {
return FormatterService.getInstance().formatTachoIcon();
}
}
单元测试:
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();
}
}
这个想法是为了配置可怕的单例的预期行为,因为测试中的类将调用它的getInstance,然后调用formatTachoIcon方法。不幸的是,这失败了,并显示一条错误消息:
when() requires an argument which has to be 'a method call on a mock'.
9条答案
按热度按时间3pmvbmvn1#
您所要求的是不可能的,因为您的遗留代码依赖于一个静态方法
getInstance()
,而Mockito不允许模拟静态方法,因此下面这行代码将无法工作有两种方法可以解决此问题:
1.使用不同的模拟工具,例如PowerMock,它允许模拟静态方法。
1.重构你的代码,这样你就不依赖于静态方法了。我能想到的实现这一点的最小侵入性的方法是向
DriverSnapshotHandler
添加一个构造函数,注入一个FormatterService
依赖项。这个构造函数将只在测试中使用,而你的生产代码将继续使用真正的单例示例。然后,您的测试应如下所示:
fv2wmkja2#
我认为这是可能的。请参阅示例how to test a singleton
试验前:
在测试之后--清理类是很重要的,因为其他测试会和被模拟的示例混淆。
测试:
lfapxunr3#
我只是想完成noscreenname的解决方案。解决方案是使用PowerMockito。因为PowerMockito可以做类似Mockito的事情,所以sometimes你可以直接使用PowerMockito。
示例代码如下所示:
单例类:
这是我的Gradle:
70gysomp4#
您的getInstance方法是静态的,因此不能使用mockito. http://cube-drone.com/media/optimized/172.png来模拟。您可能需要使用PowerMockito来模拟。尽管我不建议这样做。我会通过依赖注入来测试DriverSnapshotHandler:
单元测试:
您可能希望在@After方法中将mock设置为null,这是一个更简洁的解决方案。
mhd8tkvw5#
如果您使用的是Mockito 3.4.0+,您可以像下面这样模拟一个单例,而不需要PowerMock或其他依赖项。
我有一个名为
ProxyContext
的单例:第一个
此示例来自我之前提交的PR:https://github.com/apache/shardingsphere/pull/17796/files
您可以参考Mockito JavaDoc以了解更多详细信息:https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#48
h7appiyu6#
这是我测试单例类的方法,你只需要模拟所有的单例类,然后使用doCallRealMethod来真正调用你想测试的方法。
SingletonClass.java :
SingletonClassTest.java :
hc8w905p7#
我有一个使用反射来模拟Singleton类的变通方法。在设置测试时,您可以考虑执行以下操作。
ReflectionHelpers
是由Robolectric
在Android中提供的。然而,你总是可以编写自己的函数来帮助你实现这一点。你可以通过check the question here来获得想法。huwehgph8#
您可以使用powermock/ reflection来更改示例变量本身的值。
r1zhe5dt9#
在我看来,作为一个软件开发的初学者,可以在一个驱动类中使用依赖注入这样的机制来测试一个单例类。因为我们可以控制类的创建示例,并且仍然能够模拟静态方法。
此外,PowerMock是一个简单而干净的选项来模拟静态方法。但正如前面提到的,一个技巧,如使用单独的构造函数控制类的初始化,可以帮助实现这一点。然后在我们的测试中,我们可以传递
mock
类作为参数来初始化格式化程序服务。