如何使用 JMockit 模拟 DAO 层?

How Do I mock a DAO Layer using JMockit?

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

      public interface DummyDAO{

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

      }

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

谢谢

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

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

示例:

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

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

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

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

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

@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 次——如果遍历列表并每次都查看两个属性,你会想要这样做。

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