如何在JMockit中模拟静态方法

26

我有一个静态方法,将从类中的测试方法调用如下:

public class MyClass
{
   private static boolean mockMethod( String input )
    {
       boolean value;
       //do something to value
       return value; 
    }

    public static boolean methodToTest()
    {
       boolean getVal = mockMethod( "input" );
       //do something to getVal
       return getVal; 
    }
}

我想通过模拟mockMethod来编写测试用例,测试方法methodToTest。 尝试了以下代码,但没有输出结果。

@Before
public void init()
{
    Mockit.setUpMock( MyClass.class, MyClassMocked.class );
}

public static class MyClassMocked extends MockUp<MyClass>
{
    @Mock
    private static boolean mockMethod( String input )
    {
        return true;
    }
}

@Test
public void testMethodToTest()
{
    assertTrue( ( MyClass.methodToTest() );
} 
3个回答

37

模拟您的静态方法:

new MockUp<MyClass>()
{
    @Mock
    boolean mockMethod( String input ) // no access modifier required
    {
        return true; 
    }
};

2
你如何验证该调用? - PCH

9

模拟静态私有方法:

@Mocked({"mockMethod"})
MyClass myClass;

String result;

@Before
public void init()
{
    new Expectations(myClass)
    {
        {
            invoke(MyClass.class, "mockMethod", anyString);
            returns(result);
        }
    }
}

@Test
public void testMethodToTest()
{
    result = "true"; // Replace result with what you want to test...
    assertTrue( ( MyClass.methodToTest() );
} 

来自JavaDoc:

mockit.Invocations.invoke(Class methodOwner, String methodName, Object... methodArgs)方法

指定对给定静态方法的预期调用,以及给定参数列表。


3
因为这里缺少导入,所以我猜测invoke()方法是Deencapsulation.invoke()的静态导入。如果有其他人开头也感到困惑的话... - Ruik

5

使用JMockit(使用Delegate类)模拟静态方法的另一种方式。我觉得这更方便、优雅。

public class Service {
  public String addSuffix(String str) { // method to be tested
    return Utils.staticMethod(str);
  }
}

public class Utils {
  public static String staticMethod(String s) { // method to be mocked
    String suffix = DatabaseManager.findSuffix("default_suffix");
    return s.concat(suffix);
  }
}

public class Test {

  @Tested
  Service service;

  @Mocked
  Utils utils; // @Mocked will make sure all methods will be mocked (including static methods)

  @Test
  public void test() {
    new Expectations() {{
      Utils.staticMethod(anyString); times = 1; result = new Delegate() {
        public String staticMethod(String s) { // should have the same signature (method name and parameters) as Utils#staticMethod
          return ""; // provide custom implementation for your Utils#staticMethod
        }
      }
    }}
    
    service.addSuffix("test_value");

    new Verifications() {{
      String s;
      Utils.staticMethod(s = withCapture()); times = 1;
      assertEquals("test_value", s); // assert that Service#addSuffix propagated "test_value" to Utils#staticMethod
    }}
  }
}

参考资料:

https://jmockit.github.io/tutorial/Mocking.html#delegates https://jmockit.github.io/tutorial/Mocking.html#withCapture


1
看起来很优雅,我个人认为它还可以进一步改进。模拟的 utils 可以移动到测试方法的参数中。好处是模拟的方法仅在注入模拟参数的测试方法中生效。 - Kevin Yue
这段代码似乎无法正常工作。构造函数后需要加括号。应该使用 new Expectations() {{,而不是 new Expectations {{。另外,不能在那个层次上声明静态方法。 - Walter D
@WalterD 我调整了代码。实际上,在Delegate内部不需要使用“static”。现在应该可以工作了。 - Eugene Maysyuk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接