Test Yazma
Nette Tester için test yazmak benzersizdir çünkü her test ayrı ayrı çalıştırılabilen bir PHP betiğidir. Bu büyük bir potansiyel barındırır. Testi yazarken bile, onu kolayca çalıştırabilir ve doğru çalışıp çalışmadığını öğrenebilirsiniz. Çalışmıyorsa, IDE'de kolayca adım adım ilerleyebilir ve hatayı arayabilirsiniz.
Testi tarayıcıda bile açabilirsiniz. Ama en önemlisi – onu çalıştırarak testi gerçekleştirirsiniz. Geçip geçmediğini veya başarısız olup olmadığını hemen öğrenirsiniz.
Giriş bölümünde, diziyle çalışmanın gerçekten basit bir testini gösterdik. Şimdi test edeceğimiz kendi sınıfımızı oluşturacağız, ancak o da basit olacak.
Bir kütüphane veya proje için tipik bir dizin yapısıyla başlayalım. Testleri kodun geri kalanından ayırmak önemlidir, örneğin dağıtım için, çünkü testleri canlı sunucuya yüklemek istemeyiz. Yapı örneğin şöyle olabilir:
├── src/ # test edeceğimiz kod
│ ├── Rectangle.php
│ └── ...
├── tests/ # testler
│ ├── bootstrap.php
│ ├── RectangleTest.php
│ └── ...
├── vendor/
└── composer.json
Ve şimdi bireysel dosyaları oluşturacağız. Test edilen sınıfla başlayacağız, onu src/Rectangle.php
dosyasına yerleştireceğiz
<?php
class Rectangle
{
private float $width;
private float $height;
public function __construct(float $width, float $height)
{
if ($width < 0 || $height < 0) {
throw new InvalidArgumentException('Boyut negatif olmamalıdır.');
}
$this->width = $width;
$this->height = $height;
}
public function getArea(): float
{
return $this->width * $this->height;
}
public function isSquare(): bool
{
return $this->width === $this->height;
}
}
Ve onun için bir test oluşturacağız. Test dosyasının adı *Test.php
veya *.phpt
maskesine
uymalıdır, örneğin RectangleTest.php
varyantını seçeceğiz:
<?php
use Tester\Assert;
require __DIR__ . '/bootstrap.php';
// genel dikdörtgen
$rect = new Rectangle(10, 20);
Assert::same(200.0, $rect->getArea()); # beklenen sonuçları doğrula
Assert::false($rect->isSquare());
Gördüğünüz gibi, Assert::same()
gibi sözde doğrulama
ifadesi metotları, gerçek değerin beklenen değere karşılık geldiğini onaylamak için kullanılır.
Geriye kalan son adım bootstrap.php
dosyasıdır. Bu, tüm testler için ortak olan kodu içerir, örneğin
sınıfların otomatik yüklenmesi, ortam yapılandırması, geçici bir dizin oluşturma, yardımcı fonksiyonlar vb. Tüm
testler bootstrap'ı yükler ve ardından yalnızca test etmeye odaklanır. Bootstrap şöyle görünebilir:
<?php
require __DIR__ . '/vendor/autoload.php'; # Composer autoloader'ını yükler
Tester\Environment::setup(); # Nette Tester'ı başlatır
// ve diğer yapılandırmalar (bu sadece bir örnektir, bizim durumumuzda gerekli değildir)
date_default_timezone_set('Europe/Prague');
define('TmpDir', '/tmp/app-tests');
Belirtilen bootstrap, Composer autoloader'ının Rectangle.php
sınıfını da yükleyebileceğini
varsayar. Bu, örneğin composer.json
içinde autoload bölümünü ayarlayarak vb.
başarılabilir.
Testi şimdi komut satırından herhangi bir başka bağımsız PHP betiği gibi çalıştırabiliriz. İlk çalıştırma olası sözdizimi hatalarını ortaya çıkaracak ve hiçbir yerde yazım hatası yoksa, şunları yazdıracaktır:
$ php RectangleTest.php
OK
Eğer testteki iddiayı yanlış Assert::same(123, $rect->getArea());
olarak değiştirirsek, şu olur:
$ php RectangleTest.php Başarısız: 200.0 olmalı 123 içinde RectangleTest.php(5) Assert::same(123, $rect->getArea()); BAŞARISIZLIK
Test yazarken tüm uç durumları yakalamak iyidir. Örneğin, girdi sıfır, negatif bir sayı olduğunda, diğer durumlarda örneğin boş bir dize, null vb. olduğunda. Aslında sizi düşünmeye ve bu tür durumlarda kodun nasıl davranması gerektiğine karar vermeye zorlar. Testler daha sonra davranışı sabitler.
Bizim durumumuzda, negatif bir değer bir istisna atmalıdır, bunu Assert::exception() kullanarak doğrularız:
// genişlik negatif olmamalıdır
Assert::exception(
fn() => new Rectangle(-1, 20),
InvalidArgumentException::class,
'Boyut negatif olmamalıdır.',
);
Ve yükseklik için benzer bir test ekleriz. Son olarak, her iki boyut da aynıysa isSquare()
'in true
döndürdüğünü test ederiz. Alıştırma olarak bu tür testleri yazmayı deneyin.
Daha Okunabilir Testler
Test dosyasının boyutu büyüyebilir ve hızla okunaksız hale gelebilir. Bu nedenle, bireysel test edilen alanları ayrı fonksiyonlarda gruplamak pratiktir.
Önce daha basit, ancak zarif bir varyantı göstereceğiz, yani global test()
fonksiyonunu kullanarak. Tester
bunu otomatik olarak oluşturmaz, böylece kodunuzda aynı ada sahip bir fonksiyonunuz varsa çakışma olmaz. Onu,
bootstrap.php
dosyasında çağıracağınız setupFunctions()
metodu oluşturur:
Tester\Environment::setup();
Tester\Environment::setupFunctions();
Bu fonksiyonu kullanarak, test dosyasını adlandırılmış birimlere güzelce bölebiliriz. Çalıştırıldığında, açıklamalar sırayla yazdırılacaktır.
<?php
use Tester\Assert;
require __DIR__ . '/bootstrap.php';
test('genel dikdörtgen', function () {
$rect = new Rectangle(10, 20);
Assert::same(200.0, $rect->getArea());
Assert::false($rect->isSquare());
});
test('genel kare', function () {
$rect = new Rectangle(5, 5);
Assert::same(25.0, $rect->getArea());
Assert::true($rect->isSquare());
});
test('boyutlar negatif olmamalıdır', function () {
Assert::exception(
fn() => new Rectangle(-1, 20),
InvalidArgumentException::class,
);
Assert::exception(
fn() => new Rectangle(10, -1),
InvalidArgumentException::class,
);
});
Her testten önce veya sonra kod çalıştırmanız gerekiyorsa, onu setUp()
veya tearDown()
fonksiyonuna aktarın:
setUp(function () {
// her test() öncesinde çalışacak başlatma kodu
});
İkinci varyant nesne yönelimlidir. Sözde bir TestCase oluştururuz, bu, bireysel birimlerin test– ile başlayan adlara sahip metotları temsil ettiği bir sınıftır.
class RectangleTest extends Tester\TestCase
{
public function testGeneralOblong()
{
$rect = new Rectangle(10, 20);
Assert::same(200.0, $rect->getArea());
Assert::false($rect->isSquare());
}
public function testGeneralSquare()
{
$rect = new Rectangle(5, 5);
Assert::same(25.0, $rect->getArea());
Assert::true($rect->isSquare());
}
/** @throws InvalidArgumentException */
public function testWidthMustNotBeNegative()
{
$rect = new Rectangle(-1, 20);
}
/** @throws InvalidArgumentException */
public function testHeightMustNotBeNegative()
{
$rect = new Rectangle(10, -1);
}
}
// Test metotlarını çalıştırma
(new RectangleTest)->run();
İstisnaları test etmek için bu sefer @throw
ek açıklamasını kullandık. Daha fazlasını TestCase bölümünde öğreneceksiniz.
Yardımcı Fonksiyonlar
Nette Tester, örneğin HTML belgesinin içeriğini test etme, dosyalarla çalışan fonksiyonları test etme vb. konularda size yardımcı olabilecek birkaç sınıf ve fonksiyon içerir.
Açıklamalarını Yardımcı Sınıflar sayfasında bulabilirsiniz.
Ek Açıklamalar ve Testleri Atlama
Testlerin çalıştırılması, dosyanın başındaki phpDoc yorumu şeklindeki ek açıklamalarla etkilenebilir. Örneğin şöyle görünebilir:
/**
* @phpExtension pdo, pdo_pgsql
* @phpVersion >= 7.2
*/
Belirtilen ek açıklamalar, testin yalnızca PHP sürüm 7.2 veya üstüyle ve pdo ve pdo_pgsql PHP uzantıları mevcutsa
çalıştırılması gerektiğini söyler. Bu ek açıklamalar komut satırı
test çalıştırıcısı tarafından yönetilir, bu da koşullar karşılanmazsa testi atlar ve çıktıda
s
– skipped harfiyle işaretler. Ancak, testin manuel olarak çalıştırılmasında hiçbir etkileri yoktur.
Ek açıklamaların açıklamalarını Test Ek Açıklamaları sayfasında bulabilirsiniz.
Test, Environment::skip()
kullanarak kendi koşulunun karşılanmasına bağlı olarak da atlanabilir. Örneğin,
bu Windows'taki testleri atlar:
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
Tester\Environment::skip('UNIX gerektirir.');
}
Dizin Yapısı
Biraz daha büyük kütüphanelerde veya projelerde, test dizinini test edilen sınıfın ad alanına göre alt dizinlere ayırmanızı öneririz:
└── tests/
├── NamespaceOne/
│ ├── MyClass.getUsers.phpt
│ ├── MyClass.setUsers.phpt
│ └── ...
│
├── NamespaceTwo/
│ ├── MyClass.creating.phpt
│ ├── MyClass.dropping.phpt
│ └── ...
│
├── bootstrap.php
└── ...
Böylece testleri tek bir ad alanından, yani alt dizinden çalıştırabileceksiniz:
tester tests/NamespaceOne
Özel Durumlar
Tek bir doğrulama ifadesi metodu bile çağırmayan bir test şüphelidir ve hatalı olarak değerlendirilir:
Hata: Bu test bir doğrulama ifadesi yürütmeyi unutuyor.
Eğer testin gerçekten doğrulama ifadesi çağrısı olmadan geçerli kabul edilmesi gerekiyorsa, örneğin
Assert::true(true)
çağırın.
Ayrıca, testi bir hata mesajıyla sonlandırmak için exit()
ve die()
kullanmak da yanıltıcı
olabilir. Örneğin, exit('Bağlantıda hata')
testi 0 dönüş koduyla sonlandırır, bu da başarıyı gösterir.
Assert::fail('Bağlantıda hata')
kullanın.