İzolasyonda test
Bir eklenti geliştirirken, en iyi yolu olduğunu test etmek olmadan WordPress ortamı yükleniyor.
WordPress olmadan kolayca test edilebilecek bir kod yazarsanız, kodunuz daha iyi hale gelir .
Ünite testinden geçirilen her bileşen, yalıtılmış bir şekilde test edilmelidir : bir sınıfı test ederken, diğer tüm kodların mükemmel çalıştığını varsayarak, yalnızca o belirli sınıfı test etmeniz gerekir.
Birim testlerinin "birim" olarak adlandırılmasının nedeni budur.
Ek bir avantaj olarak, çekirdek yüklemeden, testiniz çok daha hızlı çalışacaktır.
Yapıcıdaki kancalardan kaçının
Sana verebileceğim bir ipucu, yapıcılara kanca takmamaktır. Bu, kodunuzu yalıtılmış bir şekilde test edilebilir hale getirecek şeylerden biri.
OP'de test kodunu görelim:
class CustomPostTypes extends WP_UnitTestCase {
function test_custom_post_type_creation() {
$this->assertTrue( post_type_exists( 'foo' ) );
}
}
Ve bu testin başarısız olduğunu varsayalım . Suçlu kim ?
- Kanca hiç eklenmemiş ya da uygun değil mi?
- yazı türünü kaydeden yöntem hiç veya yanlış argümanlarla çağrılmadı mı?
- WordPress'te bir hata var mı?
Nasıl geliştirilebilir?
Sınıf kodunuzun olduğunu varsayalım:
class RegisterCustomPostType {
function init() {
add_action( 'init', array( $this, 'register_post_type' ) );
}
public function register_post_type() {
register_post_type( 'foo' );
}
}
(Not: Cevabın geri kalanında sınıfın bu versiyonuna değineceğim)
Bu sınıfı yazmamın yolu, çağırmadan sınıfın örneklerini oluşturmanıza olanak sağlar add_action
.
Yukarıdaki sınıfta test edilecek 2 şey vardır:
- yöntem
init
aslındaadd_action
kendisine uygun argümanları iletmeyi çağırıyor
- yöntem
register_post_type
aslındaregister_post_type
işlevi çağırır
Yazı tipinin olup olmadığını kontrol etmeniz gerektiğini söylemedim: uygun eylemi eklerseniz ve ararsanız register_post_type
, özel yazı tipi mevcut olmalıdır : yoksa, bu bir WordPress problemidir.
Unutmayın: Eklentinizi test ederken , WordPress kodunu değil , kodunuzu test etmeniz gerekir . Testlerinizde WordPress'in (kullandığınız diğer harici kütüphaneler gibi) iyi çalıştığını varsaymanız gerekir. Birim testinin anlamı budur .
Ama ... pratikte?
WordPress yüklü değilse, yukarıdaki sınıf yöntemlerini çağırmaya çalışırsanız, önemli bir hata alırsınız, bu nedenle işlevleri alay etmeniz gerekir.
"Manuel" yöntemi
Alaycı kütüphanenizi yazabildiğinizden emin olun ya da her yöntemi alay ederek "el ile". Mümkün. Bunu nasıl yapacağınızı söyleyeceğim, ama sonra size daha kolay bir yöntem göstereceğim.
Testler çalışırken WordPress yüklü değilse, işlevlerini, örneğin add_action
veya register_post_type
.
Sahip olduğunuz önyükleme dosyanızdan yüklenen bir dosyanız olduğunu varsayalım:
function add_action() {
global $counter;
if ( ! isset($counter['add_action']) ) {
$counter['add_action'] = array();
}
$counter['add_action'][] = func_get_args();
}
function register_post_type() {
global $counter;
if ( ! isset($counter['register_post_type']) ) {
$counter['register_post_type'] = array();
}
$counter['register_post_type'][] = func_get_args();
}
Her çağrıldığında basit bir şekilde global bir diziye bir öğe eklemek için işlevleri yeniden yazdım.
Şimdi (zaten bir tane yoksa) kendi temel sınama durumu sınıfını genişletmeniz gerekir PHPUnit_Framework_TestCase
: bu, sınamalarınızı kolayca yapılandırmanıza olanak tanır.
Gibi bir şey olabilir:
class Custom_TestCase extends \PHPUnit_Framework_TestCase {
public function setUp() {
$GLOBALS['counter'] = array();
}
}
Bu şekilde, her testten önce, global sayaç sıfırlanır.
Ve şimdi test kodunuz ( yukarıda yayınlanan yeniden yazılmış sınıfa atıfta bulunuyorum ):
class CustomPostTypes extends Custom_TestCase {
function test_init() {
global $counter;
$r = new RegisterCustomPostType;
$r->init();
$this->assertSame(
$counter['add_action'][0],
array( 'init', array( $r, 'register_post_type' ) )
);
}
function test_register_post_type() {
global $counter;
$r = new RegisterCustomPostType;
$r->register_post_type();
$this->assertSame( $counter['register_post_type'][0], array( 'foo' ) );
}
}
Dikkat etmelisin:
- İki yöntemi ayrı ayrı arayabildim ve WordPress hiç yüklenmedi. Bu şekilde bir test başarısız olursa, suçlunun tam olarak kim olduğunu biliyorum .
- Dediğim gibi, burada sınıfların beklenen argümanlarla WP işlevlerini çağırdığını test ediyorum. CPT'nin gerçekten var olup olmadığını test etmeye gerek yoktur. CPT'nin varlığını test ediyorsanız, eklenti davranışınızı değil, WordPress davranışını test ediyorsunuz ...
Güzel .. ama bu bir PITA!
Evet, tüm WordPress işlevlerini elle alay etmek zorunda kalırsanız, bu gerçekten bir acıdır. Verebileceğim bazı genel tavsiyeler, mümkün olduğu kadar az WP işlevi kullanmaktır: WordPress'i yeniden yazmak zorunda değilsiniz , ancak özel sınıflarda kullandığınız soyut WP işlevlerini alay edip kolayca sınanabilmeleri için.
Örneğin, yukarıdaki örneğe ilişkin olarak, yazı tiplerini kaydeden bir sınıf yazabilir register_post_type
ve verilen argümanlarla 'init'i çağırırsınız. Bu soyutlama ile hala o sınıfı denemeniz gerekir, ancak kodunuzun yazı türlerini kaydettirdiği diğer yerlerde, o sınıfı kullanıp testlerde alay edersiniz.
Müthiş şey, eğer CPT kaydını iptal eden bir sınıf yazarsanız, bunun için ayrı bir depo oluşturabilirsiniz ve Composer gibi modern araçlar sayesinde, ihtiyaç duyduğunuz tüm projelere gömün: bir kez test edin, her yerde kullanın . Ve içinde bir hata bulursanız, tek bir yerde düzeltebilirsiniz ve basit bir şekilde kullanıldığı composer update
tüm projeler de sabitlenir.
İkinci kez: Yalıtımda test edilebilir bir kod yazmak, daha iyi kod yazmak anlamına gelir.
Ama er ya da geç WP işlevlerini bir yerde kullanmam gerekiyor ...
Tabii ki. Asla çekirdeğe paralel davranmamalısın , hiç mantıklı değil. WP işlevlerini saran sınıflar yazabilirsiniz, ancak bu sınıfların da test edilmesi gerekir. Yukarıda açıklanan "manuel" yöntem çok basit işler için kullanılabilir, ancak bir sınıf çok WP işlevi içerdiğinde bu bir acı olabilir.
Neyse ki, orada iyi şeyler yazan iyi insanlar var. En büyük WP ajanslarından biri olan 10up , eklentileri doğru şekilde test etmek isteyen insanlar için çok büyük bir kütüphane barındırıyor. Öyle WP_Mock
.
WP'nin kancalı fonksiyonlarını alay etmenizi sağlar . Testlerinize yüklediğinizi varsayalım (repo benioku bölümüne bakınız) yukarıda yazdığım test aynı şekilde olur:
class CustomPostTypes extends Custom_TestCase {
function test_init() {
$r = new RegisterCustomPostType;
// tests that the action was added with given arguments
\WP_Mock::expectActionAdded( 'init', array( $r, 'register_post_type' ) );
$r->init();
}
function test_register_post_type() {
// tests that the function was called with given arguments and run once
\WP_Mock::wpFunction( 'register_post_type', array(
'times' => 1,
'args' => array( 'foo' ),
) );
$r = new RegisterCustomPostType;
$r->register_post_type();
}
}
Basit değil mi? Bu cevap bir öğretici değildir WP_Mock
, bu yüzden daha fazla bilgi için repo benioku okuyun, ancak yukarıdaki örneğin oldukça açık olması gerektiğini düşünüyorum.
Dahası, alaycı add_action
veya register_post_type
kendiniz yazmanız veya herhangi bir global değişkeni korumanız gerekmez .
Ve WP dersleri?
WP'nin de bazı sınıfları var ve eğer testleri çalıştırdığınızda WordPress yüklü değilse, onları alay etmeniz gerekir.
Bu, alaycı işlevlerden çok daha kolaydır, PHPUnit'in nesneleri alay etmek için gömülü bir sistemi vardır, ancak burada size Mockery'i önermek istiyorum. Çok güçlü bir kütüphane ve kullanımı çok kolay. Dahası, bu bir bağımlılıktır WP_Mock
, yani eğer varsa, alaycınız da vardır.
Ama ne hakkında WP_UnitTestCase
?
WordPress test paketi WordPress çekirdeğini test etmek için oluşturulmuştur ve çekirdeğe katkıda bulunmak istiyorsanız çok önemlidir, ancak onu eklentiler için kullanmak sizi yalnızca izolasyon halinde değil test etmenizi sağlar.
Gözlerinizi WP dünyasına koyun: çok sayıda modern PHP çerçevesi ve CMS var ve bunların hiçbiri eklenti / modülleri / uzantıları (veya ne denirse) test kodunu kullanarak önermiyor.
Fabrikaları, süitin kullanışlı bir özelliğini özlüyorsanız, orada harika şeyler olduğunu bilmeniz gerekir .
Gotchas ve dezavantajları
Burada önerdiğim iş akışının eksik olduğu bir durum var: özel veritabanı testi .
Eğer (en düşük seviyesinde orada yazmak için standart WordPress tabloları ve işlevlerini kullanın Aslında, $wpdb
yöntemlere) yapmanız gerekir asla aslında veri ise yazma veri veya testinde aslında veritabanında sadece emin uygun yöntemler doğru argümanlarla dendiğini olmak.
Ancak, eklentileri orada yazmak için sorgular oluşturan özel tablolar ve işlevlerle yazabilir ve bu sorgular işe yarayıp yaramadığını test edebilir.
Bu durumlarda, WordPress test paketi size çok yardımcı olabilir ve bazı durumlarda gibi işlevleri çalıştırmak için WordPress'in yüklenmesi gerekebilir dbDelta
.
(Testler için farklı bir db kullanmanıza gerek yok, değil mi?)
Neyse ki PHPUnit size testlerin her şey bırakarak WordPress ortamı (veya bunun bir kısmını) yüklemek özel veritabanı testleri için paketi yazabilir böylece, ayrı ayrı çalıştırılabilir "suit" daki testler düzenlemenize olanak sağlar WordPress içermeyen .
Yalnızca diğer tüm eklenti sınıflarının bunlardan faydalanabileceği şekilde olabildiğince fazla veritabanı işlemi özetleyen sınıflar yazdığınızdan emin olun, böylece alay kullanarak sınıfların çoğunu veritabanıyla uğraşmadan düzgün bir şekilde test edebilirsiniz.
Üçüncü kez, kolayca yalıtım test edilebilir kod yazmak daha iyi kod yazmak demektir.
phpunit
, başarısız veya başarılı testleri görebiliyor musunuz? Yükledinizbin/install-wp-tests.sh
mi