【问题标题】:Mock objects, database access objects, and transactional scope模拟对象、数据库访问对象和事务范围
【发布时间】:2016-03-09 17:03:59
【问题描述】:

我正在使用简单的模拟来测试我的一些课程。它们是非常简单的微服务;他们从队列(顶点ID)中读取消息并调用方法。此方法打开一个事务,访问图形数据库中的一个顶点,对该顶点执行一些操作,最后关闭该事务。

这是一个示例方法:

public void updateLocation(String s) {
    ReadWriteTransaction tx = GraphHolder.readWriteTransaction();
    tx.commit(() -> {
        User user = UserFactory.getUser(s, tx);
        if (user != null) {
            Location approxLocation = getMapApi().getLocationFromPhoneNumber(user.getPhone())
            user.setLocation(approxLocation);
        }
    });
}

这依赖于一个外部 API,应该被模拟。我使用的是 EasyMock,所以设置看起来有点像这样:

public MapApi getMockedMapApi() {
    ReadWriteTransaction tx = GraphHolder.readWriteTransaction();
    return tx.commit(() -> {
        Location location = LocationFactory.createLocation(tx);
        location.setCity(CITY);
        MapApi mapApi = createMock(MapApi.class);
        expect(mapApi.getLocationFromPhoneNumber(PHONE_NUMBER)).andReturn(location);
        replay(mapApi);
        return mapApi;
    });
}

这种方法的问题是位置对象存在于与用户对象不同的事务范围内。访问或改变事务范围之外的任何属性或邻接会引发异常(与 user.setLocation(approxLocation) 一起发生)。

我还尝试模拟 Location 类并从模拟的 mapsApi 返回一个模拟的位置。这样做的问题是我无法将模拟位置顶点设置为与真实用户顶点的邻接 - 当我尝试执行此操作时,我们的图形数据库库 (tinkerpop3) 会引发错误(再次,使用 user.setLocation(approxLocation) )。

不幸的是,改变交易处理方式是不可能的。

关于这个问题的最佳解决方案有什么想法吗?

【问题讨论】:

  • 不应该Location 只是一个可以用new 实例化并独立于任何事务使用的值对象吗?它会要求一个事务,这似乎很奇怪。
  • 不,位置是一个 DAO。位置也只是一个例子,拥有在用户或公司 DAO 上运行的服务是完全有效的。

标签: java unit-testing transactions mocking graph-databases


【解决方案1】:

更新您原来的 updateLocation(String s) 以注入 Location 对象

【讨论】:

  • 这没什么区别,位置对象只能存在于事务范围内。这会将同样的问题转移到创建位置的方法上。
猜你喜欢
  • 1970-01-01
  • 2015-02-08
  • 2013-11-11
  • 2018-01-08
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
  • 1970-01-01
  • 2016-08-28
相关资源
最近更新 更多