我正在使用JUnit来测试访问Postgres数据库的存储库。
我的所有测试数据都是手动设置的,所以我确切地知道我希望在结果中得到什么值。我在测试使用current_timestamp
的语句时遇到了麻烦,例如select * from phone_number where current_timestamp <= expires;
问题是我的测试数据是常量,但current_timestamp
在每次测试执行时都会提前。
有没有办法让current_timestamp
返回一个常量值?
当然这将是几个选项之一,我还有三个解决方案:
base_date timestamp default current_time
)。所有其他数据被定义为该时期数据之后的间隔(例如,为base_date + interval '1 day'
)。知道我的测试的粗略运行时,我可以设置expires
时间戳,这些时间戳在我的测试期间肯定不会超过(例如,在base_date
之后的几小时,当运行时为秒时)。在我的测试数据中包含变量值会使检查变得更加困难。current_timestamp
并在我的所有语句中使用额外的时间戳参数,正常使用(在Java中)类似于System.currentTimeMillis()
或new java.util.Date()
(在任何情况下, '现在'),在我的测试中,我可以传递不变的日期。我不是这个解决方案的粉丝,因为a)它引入了正常使用中不需要的更改(测试之外)b)其他参数是其他错误的来源。current_timestamp
的存储过程,除非存在某个值,表示“测试模式”已打开且应返回常量。这实际上可能效果最好,但如果在Postgres中有一种简单的方法可以控制current_timestamp
返回的内容,则可能没有必要。答案 0 :(得分:1)
您可以在单元测试中包装数据库调用,而不是尝试在数据库本身中执行某些操作,或者只是为了允许进行特定测试而重构代码,而是使用类型化的文字替换查询字符串中的current_timestamp
值。例如:
public ResultSet executeQuery(String sql) {
return wrapped.executeQuery(
sql.replaceAll("\\bcurrent_timestamp\\b",
"'20160425 10:12'::timestamptz"));
}
直接实现Connection
和Statement
包装器可能会让人感到痛苦,因为这些接口定义了很多方法。如果您已经使用其他东西包装了JDBC访问,或者如果您正在使用可以创建部分模拟的模拟库(如Mockito&#39; spy()
),则可以更容易。如果您不做其中任何一项,使用java.reflect.Proxy
可能会有所帮助。