Saya memiliki tes JUnit yang ingin saya tunggu selama beberapa waktu secara sinkron. Tes JUnit saya terlihat seperti ini:
@Test
public void testExipres(){
SomeCacheObject sco = new SomeCacheObject();
sco.putWithExipration("foo", 1000);
// WAIT FOR 2 SECONDS
assertNull(sco.getIfNotExipred("foo"));
}
Saya mencoba Thread.currentThread().wait()
, tetapi itu melempar IllegalMonitorStateException (seperti yang diharapkan).
Apakah ada trik untuk itu atau apakah saya memerlukan monitor yang berbeda?
java
junit
thread-safety
Kylar
sumber
sumber
Thread.sleep
mengatakan sesuatu seperti MenggunakanThread.sleep () dapat berfungsi di banyak kasus, tetapi biasanya jika Anda menunggu, Anda sebenarnya menunggu kondisi atau status tertentu terjadi. Thread.sleep () tidak menjamin bahwa apa pun yang Anda tunggu benar-benar terjadi.
Jika Anda menunggu permintaan istirahat misalnya mungkin biasanya kembali dalam 5 detik, tetapi jika Anda mengatur tidur Anda selama 5 detik pada hari permintaan Anda kembali dalam 10 detik pengujian Anda akan gagal.
Untuk memperbaiki JayWay ini memiliki utilitas hebat yang disebut Awatility yang sempurna untuk memastikan bahwa kondisi tertentu terjadi sebelum Anda melanjutkan.
Ini memiliki api fasih yang bagus juga
await().until(() -> { return yourConditionIsMet(); });
https://github.com/jayway/awaitility
sumber
Jika penganalisis kode statis Anda (seperti SonarQube) mengeluh, tetapi Anda tidak dapat memikirkan cara lain, daripada tidur, Anda dapat mencoba dengan peretasan seperti:
Awaitility.await().pollDelay(Durations.ONE_SECOND).until(() -> true);
Ini secara konseptual salah, tetapi sama denganThread.sleep(1000)
.Cara terbaik, tentu saja, adalah dengan memberikan Callable, dengan kondisi Anda yang sesuai, daripada
true
, yang saya miliki.https://github.com/awaitility/awaitility
sumber
Duration
kelas, tetapi sejak versi 4 mereka menamainya menjadiDurations
.Anda dapat menggunakan pustaka java.util.concurrent.TimeUnit yang secara internal menggunakan Thread.sleep. Sintaksnya akan terlihat seperti ini:
@Test public void testExipres(){ SomeCacheObject sco = new SomeCacheObject(); sco.putWithExipration("foo", 1000); TimeUnit.MINUTES.sleep(2); assertNull(sco.getIfNotExipred("foo")); }
Perpustakaan ini memberikan interpretasi yang lebih jelas untuk satuan waktu. Anda dapat menggunakan 'HOURS' / 'MINUTES' / 'SECONDS'.
sumber
sleep()
memengaruhi thread pekerja?Anda juga bisa menggunakan
CountDownLatch
objek seperti yang dijelaskan di sini .sumber
Ada masalah umum: sulit untuk mengejek waktu. Selain itu, praktik yang sangat buruk untuk menempatkan kode yang berjalan / menunggu dalam waktu lama dalam pengujian unit.
Jadi, untuk membuat API penjadwalan dapat diuji, saya menggunakan antarmuka dengan implementasi nyata dan tiruan seperti ini:
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); } }
Dengan ini, Anda bisa meniru waktu dalam ujian Anda:
@Test public void testExipres() { MockClock clock = new MockClock(); SomeCacheObject sco = new SomeCacheObject(); sco.putWithExipration("foo", 1000); clock.sleep(2000) // WAIT FOR 2 SECONDS assertNull(sco.getIfNotExpired("foo")); }
Sebuah tiruan multi-threading tingkat lanjut untuk
Clock
jauh lebih kompleks, tentu saja, tetapi Anda dapat membuatnya denganThreadLocal
referensi dan strategi sinkronisasi waktu yang baik, misalnya.sumber
Jika itu adalah keharusan mutlak untuk menghasilkan penundaan dalam pengujian
CountDownLatch
adalah solusi sederhana. Di kelas pengujian Anda, nyatakan:private final CountDownLatch waiter = new CountDownLatch(1);
dan dalam pengujian jika diperlukan:
waiter.await(1000 * 1000, TimeUnit.NANOSECONDS); // 1ms
Mungkin tidak perlu dikatakan tetapi perlu diingat bahwa Anda harus menjaga waktu tunggu kecil dan tidak mengumpulkan waktu tunggu terlalu banyak.
sumber