มีปัญหาทั่วไปคือเวลาล้อเลียนมันยาก นอกจากนี้การวางโค้ดที่รัน / รอนานในการทดสอบหน่วยเป็นวิธีปฏิบัติที่แย่มาก
ดังนั้นสำหรับการสร้างกำหนดการทดสอบ API ฉันใช้อินเทอร์เฟซที่มีการใช้งานจริงและจำลองเช่นนี้:
public interface Clock {
public long getCurrentMillis();
public void sleep(long millis) throws InterruptedException;
}
public static class SystemClock implements Clock {
@Override
public long getCurrentMillis() {
return System.currentTimeMillis();
}
@Override
public void sleep(long millis) throws InterruptedException {
Thread.sleep(millis);
}
}
public static class MockClock implements Clock {
private final AtomicLong currentTime = new AtomicLong(0);
public MockClock() {
this(System.currentTimeMillis());
}
public MockClock(long currentTime) {
this.currentTime.set(currentTime);
}
@Override
public long getCurrentMillis() {
return currentTime.addAndGet(5);
}
@Override
public void sleep(long millis) {
currentTime.addAndGet(millis);
}
}
ด้วยวิธีนี้คุณสามารถเลียนแบบเวลาในการทดสอบของคุณ:
@Test
public void testExipres() {
MockClock clock = new MockClock();
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
clock.sleep(2000)
assertNull(sco.getIfNotExpired("foo"));
}
แน่นอนว่าการจำลองแบบมัลติเธรดขั้นสูงClock
นั้นซับซ้อนกว่ามาก แต่คุณสามารถสร้างได้ด้วยThreadLocal
การอ้างอิงและกลยุทธ์การซิงโครไนซ์เวลาที่ดีตัวอย่างเช่น
Thread.sleep
พูดอะไรบางอย่างเช่น การใช้ Thread.sleep ในการทดสอบโดยทั่วไปเป็นความคิดที่ไม่ดี สร้างการทดสอบที่เปราะบางซึ่งอาจล้มเหลวโดยไม่อาจคาดเดาได้ขึ้นอยู่กับสภาพแวดล้อม ("ผ่านบนเครื่องของฉัน!") หรือโหลด อย่าพึ่งพาการกำหนดเวลา (ใช้การล้อเลียน) หรือใช้ไลบรารีเช่น Awaitility สำหรับการทดสอบแบบ asynchroneous