... tidak mengetahui jika 'mock' adalah kata yang tepat.
Pokoknya, aku harus mewarisi kode-base yang saya'm mencoba untuk menulis beberapa tes untuk yang berbasis waktu. Berusaha untuk tidak menjadi terlalu samar-samar, kode ini terkait dengan melihat sejarah dari suatu item dan untuk menentukan apakah item tersebut kini telah berdasarkan batas waktu.
Di beberapa titik saya juga perlu untuk menguji menambahkan sesuatu untuk itu sejarah dan memeriksa bahwa ambang batas sekarang berubah (dan, jelas, benar).
Masalah yang saya'm memukul adalah bagian dari kode I'm pengujian menggunakan panggilan ke waktu() dan jadi saya'm menemukan itu benar-benar sulit untuk tahu persis apa waktu ambang harus berdasarkan fakta yang saya'm tidak yakin kapan tepatnya waktu itu() fungsi ini akan dipanggil.
Jadi pertanyaan saya pada dasarnya adalah ini: apakah ada cara bagi saya untuk 'override' waktu() call, atau entah bagaimana 'pura-pura keluar' waktu, seperti yang saya tes kerja di a 'yang dikenal waktu'?
Atau apakah saya hanya harus menerima kenyataan bahwa saya'm akan harus melakukan sesuatu dalam kode yang saya'm pengujian, entah bagaimana memungkinkan saya untuk memaksa untuk menggunakan waktu tertentu jika perlu?
Either way, apakah ada 'praktek umum' untuk mengembangkan waktu-sensitif fungsi itu adalah tes yang ramah?
Edit: Bagian dari masalah saya, terlalu, adalah kenyataan bahwa waktu itu hal-hal yang terjadi dalam sejarah mempengaruhi ambang batas. Berikut ini's contoh bagian dari masalah saya...
Bayangkan anda memiliki pisang dan anda're mencoba untuk bekerja keluar ketika kebutuhan untuk dimakan oleh. Let's mengatakan bahwa itu akan berakhir dalam waktu 3 hari, kecuali itu disemprot dengan beberapa bahan kimia, dalam hal ini kami menambahkan 4 hari ke kadaluwarsa, dari waktu semprot diterapkan. Kemudian, kita bisa tambahkan lagi 3 bulan sampai dengan pembekuan itu, tapi jika itu's telah beku maka kita hanya memiliki 1 hari untuk menggunakannya setelah itu mencair.
Semua aturan ini ditentukan oleh sejarah timing. Saya setuju bahwa saya bisa menggunakan Dominik's saran dari pengujian dalam beberapa detik, tapi apa yang saya historical data? Seharusnya aku hanya 'buat' on the fly?
Seperti yang anda mungkin atau mungkin tidak dapat memberitahu, aku'm masih mencoba untuk mendapatkan memahamkan semua ini 'pengujian' konsep ;)
Saya baru-baru ini datang dengan solusi lain yang lebih bagus jika anda menggunakan PHP 5.3 namespaces. Anda dapat menerapkan waktu() fungsi di dalam namespace dan menciptakan sumber daya bersama di mana anda mengatur kembali nilai tes anda. Maka setiap panggilan tidak memenuhi syarat untuk waktu() akan menggunakan fungsi baru.
Untuk membaca lebih lanjut saya jelaskan secara rinci di blog
Disclaimer: saya menulis ini perpustakaan.
Anda dapat mock waktu untuk tes menggunakan Jam dari ouzo-barang.
Dalam kode digunakan hanya:
$time = Clock::now();
Kemudian di tes:
Clock::freeze('2014-01-07 12:34');
$result = Class::getCurrDate();
$this->assertEquals('2014-01-07', $result);
Bagi anda yang bekerja dengan symfony (>= 2.8): Symfony's PHPUnit Jembatan termasuk ClockMock fitur yang menimpa built-in metode time
, microtime
, tidur
dan usleep
.
Lihat: http://symfony.com/doc/2.8/components/phpunit_bridge.html#clock-mocking
Secara pribadi, saya tetap menggunakan waktu() dalam menguji fungsi/metode. Dalam menguji kode, hanya pastikan untuk tidak menguji kesetaraan dengan waktu(), tapi hanya untuk perbedaan waktu kurang dari 1 atau 2 (tergantung pada seberapa banyak waktu fungsi yang diperlukan untuk menjalankan)
Aku harus mensimulasikan permintaan tertentu di masa depan dan masa lalu upload di aplikasi itu sendiri (tidak dalam Unit Test). Oleh karena itu semua panggilan ke \DateTime::sekarang() harus mengembalikan tanggal yang telah ditetapkan sebelumnya di seluruh aplikasi.
Aku memutuskan untuk pergi dengan ini perpustakaan https://github.com/rezzza/TimeTraveler, karena aku bisa mengejek tanggal tanpa mengubah semua kode.
\Rezzza\TimeTraveler::enable();
\Rezzza\TimeTraveler::moveTo('2011-06-10 11:00:00');
var_dump(new \DateTime()); // 2011-06-10 11:00:00
var_dump(new \DateTime('+2 hours')); // 2011-06-10 13:00:00
Dalam kebanyakan kasus ini akan dilakukan. Ini memiliki beberapa keuntungan:
It's menggunakan phpunit, tetapi anda dapat addapt ke yang lain kerangka pengujian, anda hanya perlu fungsi yang bekerja seperti assertContains() dari phpunit.
private function assertTimeEquals($testedTime, $shouldBeTime, $timeTolerance = 2)
{
$toleranceRange = range($shouldBeTime, $shouldBeTime+$timeTolerance);
return $this->assertContains($testedTime, $toleranceRange);
}
public function testGetLastLogDateInSecondsAgo()
{
// given
$date = new DateTime();
$date->modify('-189 seconds');
// when
$this->setLastLogDate($date);
// then
$this->assertTimeEquals(189, $this->userData->getLastLogDateInSecondsAgo());
}
assertTimeEquals() akan memeriksa jika array (189, 190, 191) berisi 189.
Tes ini harus dilalui untuk memperbaiki fungsi kerja JIKA melaksanakan fungsi tes membutuhkan waktu kurang dari 2 detik.
It's tidak sempurna dan super akurat, tapi's sangat sederhana dan dalam banyak kasus itu's cukup untuk menguji apa yang ingin anda uji.
Menggunakan [runkit][1] ekstensi:
define('MOCK_DATE', '2014-01-08');
define('MOCK_TIME', '17:30:00');
define('MOCK_DATETIME', MOCK_DATE.' '.MOCK_TIME);
private function mockDate()
{
runkit_function_rename('date', 'date_real');
runkit_function_add('date','$format="Y-m-d H:i:s", $timestamp=NULL', '$ts = $timestamp ? $timestamp : strtotime(MOCK_DATETIME); return date_real($format, $ts);');
}
private function unmockDate()
{
runkit_function_remove('date');
runkit_function_rename('date_real', 'date');
}
Anda bahkan dapat menguji mengejek seperti ini:
public function testMockDate()
{
$this->mockDate();
$this->assertEquals(MOCK_DATE, date('Y-m-d'));
$this->assertEquals(MOCK_TIME, date('H:i:s'));
$this->assertEquals(MOCK_DATETIME, date());
$this->unmockDate();
}
Berikut ini's selain fab's post. Aku namespace berdasarkan menimpa menggunakan eval. Dengan cara ini, aku hanya bisa menjalankannya untuk tes dan sisanya dari kode saya. Saya menjalankan sebuah fungsi yang mirip dengan:
function timeOverrides($namespaces = array()) {
$returnTime = time();
foreach ($namespaces as $namespace) {
eval("namespace $namespace; function time() { return $returnTime; }");
}
}
kemudian lulus dalam timeOverrides(array(...))
dalam tes setup sehingga saya tes hanya memiliki untuk melacak apa yang namespaces waktu() yang dipanggil.
Solusi sederhana akan menimpa PHP time() fungsi dan menggantinya dengan versi anda sendiri. Namun, anda tidak dapat menggantikan built-in fungsi PHP dengan mudah (lihat di sini).
Pendek itu, satu-satunya cara adalah abstrak time() panggilan untuk beberapa kelas/fungsi anda sendiri yang akan mengembalikan waktu yang anda butuhkan untuk pengujian.
Atau, anda bisa menjalankan uji coba sistem (sistem operasi) di mesin virtual dan mengubah waktu seluruh komputer virtual.