代码之家  ›  专栏  ›  技术社区  ›  Robert Mark Bram

通过JMockit调用私有方法来测试结果

  •  18
  • Robert Mark Bram  · 技术社区  · 11 年前

    我使用的是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,因为我不想嘲笑这个类。。只需测试调用私有方法的结果。

    6 回复  |  直到 11 年前
        1
  •  39
  •   Jeff Olson    11 年前

    我认为你把这件事搞得太复杂了。您根本不应该使用期望值块。你所需要做的就是这样:

    @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);
    }
    

    基本上,通过Deencaapsulation调用一个私有方法,并测试实际值是否与预期值相等。就像如果方法是公开的一样。没有进行嘲讽,所以不需要期望块。

        2
  •  3
  •   Robert Mark Bram    11 年前

    在这一点上,我不知道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);
    

    但你想知道什么才是真正酷的吗?如果你不打电话 设置可访问(true) ,它会爆炸 java.lang.StackOverflowError ! :)

        3
  •  2
  •   Rohit Gaikwad konda    3 年前

    由于在最新的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。
        4
  •  0
  •   zinking    6 年前

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

    但是是的,这个实用程序在其他地方也有

    org.springframework.test.util.ReflectionTestUtils
    
        5
  •  0
  •   nikhil84    4 年前

    正如@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);
        }
    
        6
  •  -2
  •   Ankur Shanbhag sachin garg    11 年前

    为什么要直接测试私有方法?大多数情况下,API方法即公共接口方法都是作为 将间接测试私有方法 以及他们。你可以把 使用私有方法的期望值断言语句 在公共方法中调用它们。所以,如果assert失败,您可以确信私有方法存在一些问题。所以你不需要单独测试。