18

我正在使用 JMockit 1.1,我想做的就是调用一个私有方法并测试返回值。但是,我无法从JMockit De-Encapsulation示例中准确理解如何执行此操作。

我要测试的方法是此类中的私有方法:

public class StringToTransaction {
   private List<String> parseTransactionString(final String input) {
      // .. processing
      return resultList;
   }
}

我的测试代码如下。

@Test
public void testParsingForCommas() {
   final StringToTransaction tested = new StringToTransaction();
   final List<String> expected = new ArrayList<String>();
   // Add expected strings list here..
   new Expectations() {
      {
         invoke(tested, "parseTransactionString", "blah blah");
         returns(expected);
      }
   };
}

我得到的错误是:

java.lang.IllegalStateException:此时缺少对模拟类型的调用;请确保此类调用仅在声明合适的模拟字段或参数之后出现

也许我在这里误解了整个API,因为我不认为我想模拟类..只是测试调用私有方法的结果。

4

6 回答 6

39

我认为你让这太复杂了。您根本不应该使用 Expectations 块。您需要做的就是这样的:

@Test
public void testParsingForCommas() {
   StringToTransaction tested = new StringToTransaction();
   List<String> expected = new ArrayList<String>();
   // Add expected strings list here..

   List<String> actual = Deencapsulation.invoke(tested, "parseTransactionString", "blah blah");
   assertEquals(expected, actual);
}

基本上,通过 Deencapsulation 调用私有方法并测试实际是否等于预期。就像方法是公开的一样。没有进行任何模拟,因此不需要 Expectations 块。

于 2013-03-25T05:23:11.353 回答
3

在这一点上,我不知道 JMockit 是否可以或应该用于此。测试我的私有方法可以用普通的反射来完成,尽管我开始这个练习是为了了解 JMockit(并测试我的代码)。如果 JMockit 不能用于此,这里是我可以使用反射的方法。

@Test
public void testParsingForCommas() throws Exception {
   StringToTransaction tested = new StringToTransaction();
   ArrayList<String> expected = new ArrayList<>();
   expected.add("Test");

   Method declaredMethod =
         tested.getClass().getDeclaredMethod("parseTransactionString",
               String.class);
   declaredMethod.setAccessible(true);
   Object actual = declaredMethod.invoke(tested, "blah blah");
   assertEquals(expected, actual);
}

调用在setAccessible(true)这里很重要,否则invoke调用私有方法时会爆炸。

declaredMethod.setAccessible(true);

但是你想知道什么是真正的酷吗?如果你不打电话setAccessible(true),它会炸毁一个java.lang.StackOverflowError!:)

于 2013-03-25T09:56:57.870 回答
1

由于最新的 Jmockit 中不允许模拟私有方法。可以模拟该私有方法中使用的 API 作为一种解决方法,而不是模拟私有方法。

此解决方法也可以视为最终解决方案。

示例:
实际类:

class A {

  private int getId(String name){  //private method
      return DAOManager.getDao().getId(name);  //Call to non-private method can be mocked.
  }
}  

测试类:

public class ATest{

  @Before
  public void setUp(){
    new MockDAOManager();
  }

  //Mock APIs used by the private method `getId`.
  public static class MockDAOManager extends MockUp<MockDAOManager>{
     static mocked_user_id = 101;

     @Mock
     public DAOManager getDao() throws Exception{
          return new DAOManager();
     }

     @Mock
     public Integer getId(String name){
         return mocked_user_id;
     }
  }
}

笔记:

  • 如果您没有这样的逻辑(私有方法调用另一个非私有方法),那么您可能必须重构您的代码,否则这将不起作用。
  • 这里DAOManager.getDao().getId(name)不是私有 API。
  • 可能需要模拟该私有方法使用的所有 API。
于 2021-05-25T02:46:23.577 回答
0

正如@Jeff Olson 所提到的,您还可以通过声明它们来调用 bean 的私有方法@Tested

这是一个例子:

// Java

    @Tested
    private YourServiceImplClass serviceImpl;

    @Test
    public void testPrivateMethod() {
   
          List<String> expected = new ArrayList<String>();
          // Add expected strings list here..

          List<String> actual = Deencapsulation.invoke(serviceImpl, "yourPrivateMethod", "arguments");
          assertEquals(expected, actual);
    }
于 2018-11-30T18:19:32.663 回答
0

从 1.35(?) 开始,jmockit 删除了该辅助方法。因为它不再有用(我不太明白)

但是,是的,此实用程序在其他地方可用

org.springframework.test.util.ReflectionTestUtils
于 2018-10-17T01:58:54.010 回答
-2

为什么要直接测试私有方法?大多数情况下,API 方法(即公共接口方法)是单元测试的,因为私有方法也将与它们一起被间接测试。您可以将断言语句与来自私有方法的预期值放在公共方法中调用它们的位置。因此,如果断言失败,您可以确定私有方法存在一些问题。所以你不需要单独测试它。

于 2013-03-24T06:23:54.913 回答