Joda Time memiliki DateTimeUtils.setCurrentMillisFixed () yang bagus untuk meniru waktu.
Ini sangat praktis dalam ujian.
Apakah ada yang setara di java.time API Java 8 ?
Joda Time memiliki DateTimeUtils.setCurrentMillisFixed () yang bagus untuk meniru waktu.
Ini sangat praktis dalam ujian.
Apakah ada yang setara di java.time API Java 8 ?
Yang paling dekat adalah Clock
objeknya. Anda dapat membuat objek Jam menggunakan waktu yang Anda inginkan (atau dari waktu Sistem saat ini). Semua objek date.time memiliki now
metode kelebihan beban yang mengambil objek jam sebagai gantinya untuk waktu saat ini. Jadi Anda dapat menggunakan injeksi ketergantungan untuk menyuntikkan Jam dengan waktu tertentu:
public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}
Lihat Clock JavaDoc untuk detail selengkapnya
Clock.fixed
berguna dalam pengujian, sementaraClock.system
atauClock.systemUTC
mungkin digunakan dalam aplikasi.Saya menggunakan kelas baru untuk menyembunyikan
Clock.fixed
pembuatan dan menyederhanakan tes:public class TimeMachine { private static Clock clock = Clock.systemDefaultZone(); private static ZoneId zoneId = ZoneId.systemDefault(); public static LocalDateTime now() { return LocalDateTime.now(getClock()); } public static void useFixedClockAt(LocalDateTime date){ clock = Clock.fixed(date.atZone(zoneId).toInstant(), zoneId); } public static void useSystemDefaultZoneClock(){ clock = Clock.systemDefaultZone(); } private static Clock getClock() { return clock ; } }
public class MyClass { public void doSomethingWithTime() { LocalDateTime now = TimeMachine.now(); ... } }
@Test public void test() { LocalDateTime twoWeeksAgo = LocalDateTime.now().minusWeeks(2); MyClass myClass = new MyClass(); TimeMachine.useFixedClockAt(twoWeeksAgo); myClass.doSomethingWithTime(); TimeMachine.useSystemDefaultZoneClock(); myClass.doSomethingWithTime(); ... }
sumber
getClock()
metode tersebut dan menggunakan bidang tersebut secara langsung. Metode ini hanya menambahkan beberapa baris kode.Saya menggunakan lapangan
private Clock clock;
lalu
dalam kode produksi saya. Lalu saya menggunakan Mockito dalam pengujian unit saya untuk mengejek Jam menggunakan Clock.fixed ():
@Mock private Clock clock; private Clock fixedClock;
Mengejek:
Tuntutan:
sumber
Saya menemukan menggunakanClock
kekacauan kode produksi Anda.Anda dapat menggunakan JMockit atau PowerMock untuk meniru pemanggilan metode statis dalam kode pengujian Anda. Contoh dengan JMockit:
@Test public void testSth() { LocalDate today = LocalDate.of(2000, 6, 1); new Expectations(LocalDate.class) {{ LocalDate.now(); result = today; }}; Assert.assertEquals(LocalDate.now(), today); }
EDIT : Setelah membaca komentar pada jawaban Jon Skeet untuk pertanyaan serupa di sini JADI saya tidak setuju dengan diri saya di masa lalu. Lebih dari segalanya, argumen tersebut meyakinkan saya bahwa Anda tidak dapat memparalelkan pengujian ketika Anda mengejek metode statis.
Anda masih bisa / harus menggunakan ejekan statis jika Anda harus berurusan dengan kode lama.
sumber
Saya butuh
LocalDate
contoh, bukanLocalDateTime
.Dengan alasan seperti itu saya membuat kelas utilitas berikut:
public final class Clock { private static long time; private Clock() { } public static void setCurrentDate(LocalDate date) { Clock.time = date.toEpochDay(); } public static LocalDate getCurrentDate() { return LocalDate.ofEpochDay(getDateMillis()); } public static void resetDate() { Clock.time = 0; } private static long getDateMillis() { return (time == 0 ? LocalDate.now().toEpochDay() : time); } }
Dan penggunaannya seperti:
class ClockDemo { public static void main(String[] args) { System.out.println(Clock.getCurrentDate()); Clock.setCurrentDate(LocalDate.of(1998, 12, 12)); System.out.println(Clock.getCurrentDate()); Clock.resetDate(); System.out.println(Clock.getCurrentDate()); } }
Keluaran:
2019-01-03 1998-12-12 2019-01-03
Mengganti semua kreasi
LocalDate.now()
keClock.getCurrentDate()
dalam proyek.Karena ini adalah aplikasi boot musim semi . Sebelum
test
eksekusi profil, cukup setel tanggal yang telah ditentukan untuk semua tes:public class TestProfileConfigurer implements ApplicationListener<ApplicationPreparedEvent> { private static final LocalDate TEST_DATE_MOCK = LocalDate.of(...); @Override public void onApplicationEvent(ApplicationPreparedEvent event) { ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment(); if (environment.acceptsProfiles(Profiles.of("test"))) { Clock.setCurrentDate(TEST_DATE_MOCK); } } }
Dan tambahkan ke spring.factories :
sumber
Berikut cara kerja untuk mengganti waktu sistem saat ini ke tanggal tertentu untuk tujuan pengujian JUnit di aplikasi web Java 8 dengan EasyMock
Joda Time pasti menyenangkan (terima kasih Stephen, Brian, Anda telah membuat dunia kita menjadi tempat yang lebih baik) tetapi saya tidak diizinkan untuk menggunakannya.
Setelah beberapa percobaan, saya akhirnya menemukan cara untuk meniru waktu ke tanggal tertentu di Java.time API Java 8 dengan EasyMock
Inilah yang perlu dilakukan:
Apa yang perlu dilakukan di kelas yang diuji
Langkah 1
Tambahkan
java.time.Clock
atribut baru ke kelas yang diujiMyService
dan pastikan atribut baru akan diinisialisasi dengan benar pada nilai default dengan blok instantiation atau konstruktor:import java.time.Clock; import java.time.LocalDateTime; public class MyService { // (...) private Clock clock; public Clock getClock() { return clock; } public void setClock(Clock newClock) { clock = newClock; } public void initDefaultClock() { setClock( Clock.system( Clock.systemDefaultZone().getZone() // You can just as well use // java.util.TimeZone.getDefault().toZoneId() instead ) ); } { initDefaultClock(); } // initialisation in an instantiation block, but // it can be done in a constructor just as well // (...) }
Langkah 2
Masukkan atribut baru
clock
ke dalam metode yang memanggil tanggal-waktu saat ini. Misalnya, dalam kasus saya, saya harus melakukan pemeriksaan apakah tanggal yang disimpan dalam database terjadi sebelumnyaLocalDateTime.now()
, yang saya ganti denganLocalDateTime.now(clock)
, seperti:import java.time.Clock; import java.time.LocalDateTime; public class MyService { // (...) protected void doExecute() { LocalDateTime dateToBeCompared = someLogic.whichReturns().aDate().fromDB(); while (dateToBeCompared.isBefore(LocalDateTime.now(clock))) { someOtherLogic(); } } // (...) }
Apa yang perlu dilakukan di kelas pengujian
LANGKAH 3
Di kelas pengujian, buat objek jam tiruan dan masukkan ke dalam instance kelas yang diuji tepat sebelum Anda memanggil metode yang diuji
doExecute()
, lalu setel ulang kembali setelahnya, seperti ini:import java.time.Clock; import java.time.LocalDateTime; import java.time.OffsetDateTime; import org.junit.Test; public class MyServiceTest { // (...) private int year = 2017; // Be this a specific private int month = 2; // date we need private int day = 3; // to simulate. @Test public void doExecuteTest() throws Exception { // (...) EasyMock stuff like mock(..), expect(..), replay(..) and whatnot MyService myService = new MyService(); Clock mockClock = Clock.fixed( LocalDateTime.of(year, month, day, 0, 0).toInstant(OffsetDateTime.now().getOffset()), Clock.systemDefaultZone().getZone() // or java.util.TimeZone.getDefault().toZoneId() ); myService.setClock(mockClock); // set it before calling the tested method myService.doExecute(); // calling tested method myService.initDefaultClock(); // reset the clock to default right afterwards with our own previously created method // (...) remaining EasyMock stuff: verify(..) and assertEquals(..) } }
Periksa dalam mode debug dan Anda akan melihat tanggal 3 Feb 2017 telah dimasukkan dengan benar ke dalam
myService
instance dan digunakan dalam instruksi perbandingan, dan kemudian telah disetel ulang dengan benar ke tanggal saat ini denganinitDefaultClock()
.sumber
Contoh ini bahkan menunjukkan cara menggabungkan Instan dan Waktu Lokal ( penjelasan mendetail tentang masalah dengan konversi )
Kelas yang sedang diuji
import java.time.Clock; import java.time.LocalTime; public class TimeMachine { private LocalTime from = LocalTime.MIDNIGHT; private LocalTime until = LocalTime.of(6, 0); private Clock clock = Clock.systemDefaultZone(); public boolean isInInterval() { LocalTime now = LocalTime.now(clock); return now.isAfter(from) && now.isBefore(until); } }
Tes Groovy
import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import java.time.Clock import java.time.Instant import static java.time.ZoneOffset.UTC import static org.junit.runners.Parameterized.Parameters @RunWith(Parameterized) class TimeMachineTest { @Parameters(name = "{0} - {2}") static data() { [ ["01:22:00", true, "in interval"], ["23:59:59", false, "before"], ["06:01:00", false, "after"], ]*.toArray() } String time boolean expected TimeMachineTest(String time, boolean expected, String testName) { this.time = time this.expected = expected } @Test void test() { TimeMachine timeMachine = new TimeMachine() timeMachine.clock = Clock.fixed(Instant.parse("2010-01-01T${time}Z"), UTC) def result = timeMachine.isInInterval() assert result == expected } }
sumber
Dengan bantuan PowerMockito untuk uji boot musim semi, Anda dapat membuat tiruan file
ZonedDateTime
. Anda membutuhkan yang berikut ini.Anotasi
Di kelas pengujian, Anda perlu menyiapkan layanan yang menggunakan ekstensi
ZonedDateTime
.@RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(SpringRunner.class) @PrepareForTest({EscalationService.class}) @SpringBootTest public class TestEscalationCases { @Autowired private EscalationService escalationService; //... }
Kasus cobaan
Dalam pengujian, Anda dapat menyiapkan waktu yang diinginkan, dan mendapatkannya sebagai respons dari panggilan metode.
@Test public void escalateOnMondayAt14() throws Exception { ZonedDateTime preparedTime = ZonedDateTime.now(); preparedTime = preparedTime.with(DayOfWeek.MONDAY); preparedTime = preparedTime.withHour(14); PowerMockito.mockStatic(ZonedDateTime.class); PowerMockito.when(ZonedDateTime.now(ArgumentMatchers.any(ZoneId.class))).thenReturn(preparedTime); // ... Assertions }
sumber