【问题标题】:How Do I mock a DAO Layer using JMockit?如何使用 JMockit 模拟 DAO 层?
【发布时间】:2016-05-26 15:48:35
【问题描述】:

我正在尝试模拟一个看起来像这样的 DAO 层接口...

      public interface DummyDAO{

     public List<VO> getSearchCriteria(String Id, Integer version) throws Exception;

      }

在实现部分,我运行一个查询,它会根据该查询为我获取一个 Value 对象列表。如何模拟来自数据库的 VO 列表。有没有一种简单的方法可以做到这一点?我试图鼓励我的团队使用 Jmockit,但我仍然是这个模拟工具的新手。如果您需要更多信息,请告诉我。

谢谢

【问题讨论】:

    标签: java unit-testing junit mocking jmockit


    【解决方案1】:

    这里的答案可能部分取决于 CUT(被测代码)如何使用 List&lt;VO&gt;。例如,如果您的代码是 RESTful 服务,仅充当代理并将此 List&lt;VO&gt; 返回给用户,而不检查内容或任何内容,那么这就足够了:

    @Tested CUT cut;
    @Injectable DummyDAO dao;
    @Injectable List<VO> res;
    
    @Test
    public void testSomething() throws Exception {
        new Expectations() {{
            dao.getSearchCriteria(anyString, anyInt); result = res; 
        }};
        List<VO> output = cut.methodBeingTested();
        // assertions go here, like that output and res are the same
        // you can also put Verifications here
    }
    

    如果您希望对 VOs 进行分析,那么事情可能会变得更加复杂,例如:

    @Tested CUT cut;
    @Injectable DummyDAO dao;
    @Mocked VO vo;
    
    @Test
    public void testSomething() throws Exception {
        final List<VO> res = new ArrayList<VO>();
        Collections.addAll(res, vo, vo, vo, vo);
        new Expectations() {{
            dao.getSearchCriteria(anyString, anyInt); result = res;
        }};
    
        new Expectations(4) {{
            vo.getFoo(); returns(5, 47, 13, -7);
        }};
    
        cut.methodBeingTested();
        // assertions go here, like that you handled the negative number properly
        // you can also put Verifications here
    }
    

    注意这里我没有模拟List——如果您正在执行更复杂的操作,最好坚持使用真正的List,而不必模拟它的所有操作。我模拟了一个 VO 并将其多次添加到列表中——这没关系,因为每次检查它时它的行为都会有所不同,因此似乎是不同的 VO

    检查,因为它发生了 4 次,所以我搬到了另一个 Expectations 块,因为您预计它会发生 4 次。我这样做只是为了展示期望块,因为在这种情况下,它可以通过在原始块中添加 vo.getFoobar(); times=4; returns(5, 47, 13, -7); 来轻松完成......或者,第二个块可能看起来像

        new StrictExpectations(4) {{
            vo.getFoo(); returns(5, 47, 13, -7);
            vo.getBar(); returns("foo", "bar", "baz", "quux");
        }};
    

    在这种情况下,times 字段将不起作用,您必须将它放在单独的块中 - 该块表示它希望 getFoo()getBar() 交替调用,恰好 4 次-- 就像遍历一个列表并每次都查看这两个属性时所做的那样。

    我希望我已经让你深思了;在不了解您的具体用例的情况下,我自己无法更具体。

    【讨论】:

    • 感谢您的提醒。这很有帮助。
    • +1 但应该是@Injectable DummyDAO dao(不是“@Mocked”),这样被模拟的dao实例就会被注入到@Tested CUT cut对象中。
    • 过失。你(当然!)是对的。我会修复它。感谢您的洞察力和出色的工具!
    • 假设我有一个 DAOImpl 类,其中有一个 getMethod() 。如果我必须在这个类中调用这个方法,我需要在类中添加 Tested 和 Injectable 注释吗?
    • @Tested 仅适用于您实际测试的类。除非您正在测试 DAOImpl,否则请避开。不过,@Injected 适合这里。声明一个@Injectable DAOImpl 并在任何类型的 StrictExpectations/NonStrictExpectations/Expectations 块中记录您的期望。
    【解决方案2】:

    一种简单的方法是使用 Mockito.spy() 。spy 方法为您的实例创建一个代理,让您有机会模拟一种方法的行为。

    您可以创建一个列表,当您调用您的 dao 方法时将返回该列表。

    例子:

    yourDao = spy(new YourDaoImplementation())
            doReturn(yourExampleList).when(yourDao).getSearchCriteria(any(String.class), any(Integer.class));
    

    如果你真的想测试你的 dao,你可以使用一个轻量级的数据库作为 HSQLDB

    【讨论】:

    • 是的,你是对的,我的解决方案是使用 Mockito 而不是 JMockit
    猜你喜欢
    • 2018-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-27
    相关资源
    最近更新 更多