如何在不访问私有变量的情况下测试jUnit测试中的时间传递?

All*_*an5 5 java tdd junit unit-testing

我正在测试一个我需要一定时间才能通过的课程才能检查结果.具体来说,我需要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));
}
Run Code Online (Sandbox Code Playgroud)

除了修改accessTime私有变量(通过创建setAccessTime setter或反射)或在单元测试中插入sleep之外,是否可以测试这个?

编辑2012年4月11日

我特意试图测试我的SessionManager对象在经过一段特定时间后清除会话.我连接的数据库将在一段固定的时间后丢弃连接.当我接近该超时时,SessionManager对象将通过调用数据库上的"finalize session"过程来清除会话,并从其内部列表中删除会话.

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

对connMgr(ConnectionManager对象)的调用有点复杂,但我正在重构遗留代码的过程,而且它正是它现在的样子.Session对象存储与数据库的连接以及一些关联数据.

Gis*_*shu 4

  • 该测试可以进行一些重构以使意图更加清晰。如果我的理解是正确的话...

public void TestClearSessionsMaintainsSessionsUnlessLastAccessTimeIsOverThreshold() {

    final int timeout = 1;
    final String sessionId = "test";
    sessionMgr = GetSessionManagerWithTimeout(timeout);
    DBSession session = CreateSession(sessionMgr, sessionId);

    sessionMgr.clearSessions();
    assertNotNull(sessionMgr.getSession(sessionId));

    session.setAccessTime(PastInstantThatIsOverThreshold()); // MODIFY PRIVATE VARIABLE VIA PROTECTED SETTER
    sessionMgr.clearSessions();
    assertNull(sessionMgr.getSession(sessionId));
}
Run Code Online (Sandbox Code Playgroud)
  • 现在讨论无需暴露私有状态的测试问题
    • 现实生活中私有变量是如何修改的?您是否可以调用其他一些公共方法来更新访问时间?
    • 既然时钟/时间是一个重要的概念,为什么不将其明确作为一个角色呢?因此,您可以将 Clock 对象传递给 Session,它用它来更新其内部访问时间。在您的测试中,您可以传入一个 MockClock,其 getCurrentTime() 方法将返回您想要的任何值。我正在编写模拟语法..因此请更新您正在使用的内容。

public void TestClearSessionsMaintainsSessionsUnlessLastAccessTimeIsOverThreshold() {

      final int timeout = 1;
      final String sessionId = "test";
      expect(mockClock).GetCurrentTime(); willReturn(CurrentTime());
      sessionMgr = GetSessionManagerWithTimeout(timeout, mockClock);
      DBSession session = CreateSession(sessionMgr, sessionId);

      sessionMgr.clearSessions();
      assertNotNull(sessionMgr.getSession(sessionId));

      expect(mockClock).GetCurrentTime(); willReturn(PastInstantThatIsOverThreshold());
      session.DoSomethingThatUpdatesAccessTime();
      sessionMgr.clearSessions();
      assertNull(sessionMgr.getSession(sessionId));
}
Run Code Online (Sandbox Code Playgroud)