有没有办法在junit中测试时模拟静态util方法?
我知道Powermock可以模拟静态调用;但我不想使用Powermock。
还有其他选择吗?
答案 0 :(得分:10)
(我假设你可以使用Mockito)我没有任何专注,但我倾向于使用以下策略:
1)在被测试的类中,使用包装静态调用本身的包级别方法调用替换静态直接调用:
public class ToBeTested{
public void myMethodToTest(){
...
String s = makeStaticWrappedCall();
...
}
String makeStaticWrappedCall(){
return Util.staticMethodCall();
}
}
2)在测试时监视被测试的类并模拟包装的包级别方法:
public class ToBeTestedTest{
@Spy
ToBeTested tbTestedSpy = new ToBeTested();
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
@Test
public void myMethodToTestTest() throws Exception{
// Arrange
doReturn("Expected String").when(tbTestedSpy).makeStaticWrappedCall();
// Act
tbTestedSpy.myMethodToTest();
}
}
答案 1 :(得分:4)
当您拥有静态代码时,会给您的单元测试带来麻烦;所以你觉得你必须“嘲笑它”,你有这些选择:
换句话说:如果你想使用一个模拟框架,你必须使用上面列出的那个。一方面,这绝对是公平的。 static 是Java语言的一部分;那么为什么不使用一个允许你处理它的框架呢?
但当然:您的生产代码中仍然存在静态调用。导致紧耦合,并阻止多态。
所以:如果你可以摆脱静态调用(即使只是使用其他答案中建议的解决方法) - 那就更好了。如果不是:Mockito无能为力;你需要字节码操作的神奇之处。 JVM代理。
答案 2 :(得分:1)
您可以使用Mockito
(自3.4.0版本开始)来模拟静态方法。
给出一个类Foo
:
class Foo{
static String method() {
return "foo";
}
}
这是测试:
@Test
void testMethod() {
assertEquals("foo", Foo.method());
try (MockedStatic mocked = Mockito.mockStatic(Foo.class)) {
mocked.when(Foo::method).thenReturn("bar");
assertEquals("bar", Foo.method());
mocked.verify(Foo::method);
}
assertEquals("foo", Foo.method());
}
这需要依赖项org.mockito:mockito-inline:3.4.0
或更高版本。
答案 3 :(得分:0)
我做得和Maciej在上面他的回答中所建议的类似,因此很幸运。在Java8中,我喜欢用功能接口包装这些静态方法,以使其更直接地进行注入或模拟。例如:
public class MyClass {
private MyStaticWrapper staticWrapper;
public MyClass(final MyStaticWrapper staticWrapper) {
this.staticWrapper = staticWrapper;
}
public void main() {
...
staticWrapper.doSomething();
...
}
}
public interface MyStaticWrapper {
default void doSomething() {
Util.annoyingUntestableStaticFunction();
}
}