【发布时间】:2012-04-05 03:09:23
【问题描述】:
我正在对一门课程进行单元测试,我需要一定的时间才能通过检查结果。具体来说,我需要通过 x 分钟才能判断测试是否有效。我已经读过,在单元测试中我们应该测试接口而不是实现,所以我们不应该访问私有变量,但是除了在我的单元测试中休眠之外,我不知道如何在不修改私有变量的情况下进行测试。
我的测试是这样设置的:
@Test
public void testClearSession() {
final int timeout = 1;
final String sessionId = "test";
sessionMgr.setTimeout(timeout);
try {
sessionMgr.createSession(sessionId);
} catch (Exception e) {
e.printStackTrace();
}
DBSession session = sessionMgr.getSession(sessionId);
sessionMgr.clearSessions();
assertNotNull(sessionMgr.getSession(sessionId));
Calendar accessTime = Calendar.getInstance();
accessTime.add(Calendar.MINUTE, - timeout - 1);
session.setAccessTime(accessTime.getTime()); // MODIFY PRIVATE VARIABLE VIA PROTECTED SETTER
sessionMgr.clearSessions();
assertNull(sessionMgr.getSession(sessionId));
}
除了修改 accessTime 私有变量(通过创建 setAccessTime 设置器或反射)或在单元测试中插入睡眠之外,是否可以对此进行测试?
2012 年 4 月 11 日编辑
我特别想测试我的 SessionManager 对象是否在特定时间段过后清除会话。我正在连接的数据库将在一段固定时间后断开连接。当我接近该超时时,SessionManager 对象将通过在数据库上调用“最终会话”过程来清除会话,并从其内部列表中删除会话。
SessionManager 对象设计为在单独的线程中运行。我正在测试的代码如下所示:
public synchronized void clearSessions() {
log.debug("clearSessions()");
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, - timeout);
Iterator<Entry<String, DBSession>> entries = sessionList.entrySet().iterator();
while (entries.hasNext()) {
Entry<String, DBSession> entry = entries.next();
DBSession session = entry.getValue();
if (session.getAccessTime().before(cal.getTime())) {
// close connection
try {
connMgr.closeconn(session.getConnection(), entry.getKey());
} catch (Exception e) {
e.printStackTrace();
}
entries.remove();
}
}
}
对 connMgr(ConnectionManager 对象)的调用有点令人费解,但我正在重构遗留代码,目前就是这样。 Session 对象存储与数据库的连接以及一些相关数据。
【问题讨论】:
-
附注:单元测试通常不应该测试任何在后台工作的东西(在单独的线程中)。因此,您可以拆分逻辑并在另一个线程中运行它。然后第一个可以通过单元测试轻松测试,第二个 - 通过功能/验收测试
-
您正在测试的代码是否调用
System.getCurrentTimeMillis()(或类似的名称,例如new Date())?如果是这样,这就是一种可测试性反模式;您想将此委托给可以注入的“时间源”类。然后,您可以使用模拟时间源进行测试。如果您可以发布您尝试测试的源代码,我可以帮助您了解如何执行我的建议。 -
@DavidWallace - 我只是假设 GetInstance 就是那个电话。 JavaDocs 确认
Calendar's getInstance method returns a Calendar object whose time fields have been initialized with the current date and time: -
对,但我认为你不能注入它;
getInstance是静态的。 OP 需要的是一个可以为您提供当前时间的类(可选为Calendar),但也可以模拟并注入到 SUT 中。 -
我建议在这里使用 Jodatime:它的 DateTimeUtils 类允许你模拟时间的来源。
标签: java unit-testing junit tdd