Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Testlerin Nasıl Çalıştırılacağını Kontrol Etme

Tıpkı cargo run komutunun kodunuzu derleyip ardından üretilen ikili dosyayı çalıştırması gibi, cargo test komutu da kodunuzu test modunda derler ve üretilen test ikili dosyasını çalıştırır. cargo test tarafından üretilen ikilinin varsayılan davranışı, tüm testleri paralel olarak çalıştırmak ve testlerin çalışması sırasında üretilen çıktıyı yakalamaktır; böylece bu çıktı ekranda görüntülenmez ve test sonuçlarıyla ilgili çıktıyı okumak kolaylaşır. Bununla birlikte, bu varsayılan davranışı değiştirmek için komut satırı seçenekleri belirtebilirsiniz.

Bazı komut satırı seçenekleri cargo test komutuna, bazıları ise üretilen test ikili dosyasına iletilir. Bu iki argüman türünü birbirinden ayırmak için önce cargo test’e gidecek argümanları, ardından -- ayırıcısını ve sonrasında test ikilisine gidecek argümanları sıralarsınız. cargo test --help komutunu çalıştırmak cargo test ile kullanabileceğiniz seçenekleri listelerken, cargo test -- --help komutunu çalıştırmak ayırıcıdan sonra kullanabileceğiniz seçenekleri gösterir. Bu seçenekler rustc Kitabı’nın “Tests” bölümünde de belgelenmiştir.

Not: Pratikte -- ayırıcısının solundaki ve sağındaki seçenekler iki farklı katmanı kontrol eder:

  • -- öncesi (cargo test bayrakları): Cargo’nun hangi test hedeflerini derleyip çalıştıracağını belirler. Örneğin cargo test --lib yalnızca kütüphane birim testlerini, cargo test --test entegrasyon_testi ise yalnızca belirtilen entegrasyon testi dosyasını derleyip çalıştırır (belgelendirme testlerini ve diğer hedefleri atlar).
  • -- sonrası (test çalıştırıcısı bayrakları): Derlenen test ikilisinin testleri yürütme ve çıktıyı raporlama biçimini değiştirir. Bu bölümde ele alacağımız --test-threads, --show-output, --ignored ve --include-ignored bayraklarının yanı sıra; standart çıktıyı hiç yakalamadan anlık olarak terminale yazdırmak için --no-capture (veya eski adıyla --nocapture) ya da alt dizgi araması yerine modül yolunu da içeren tam test adıyla eşleşme yapmak için --exact (cargo test tests::yuz -- --exact gibi) bayraklarını bu kısımda kullanabilirsiniz. İki katmanın bayraklarını aynı komutta birleştirmek de mümkündür: örneğin cargo test --lib -- --show-output.

Testleri Paralel veya Ardışık Olarak Çalıştırma

Birden fazla testi çalıştırdığınızda bunlar varsayılan olarak thread’ler (iş parçacıkları) aracılığıyla paralel biçimde çalışır; bu sayede testler daha kısa sürede tamamlanır ve çok daha hızlı geri bildirim alırsınız. Testler aynı anda çalıştığı için testlerinizin birbirine ya da paylaşılan herhangi bir duruma bağımlı olmadığından emin olmalısınız; geçerli çalışma dizini veya çevre değişkenleri gibi ortak bir ortam da bu paylaşılan duruma dahildir.

Örneğin testlerinizin her birinin diskte test-ciktisi.txt adında bir dosya oluşturan ve bu dosyaya veri yazan bir kod çalıştırdığını düşünelim. Ardından her test bu dosyadaki veriyi okur ve dosyanın —her testte farklı olan— belirli bir değeri içerdiğini doğrular. Testler aynı anda çalıştığı için, bir test dosyaya yazma ile dosyayı okuma işlemleri arasındayken başka bir test aynı dosyanın üzerine yazabilir. Bu durumda dosyayı ilk yazan test, kendi beklediği içerik değiştirilmiş olduğu için başarısız olabilir. Sorun, sınanan işlevden değil, paralel testlerin aynı dosyayı paylaşmasından kaynaklanır. Çözümlerden biri her testin farklı bir dosyaya yazmasını sağlamaktır; diğer bir çözüm ise testleri teker teker çalıştırmaktır.

Testleri paralel çalıştırmak istemiyorsanız veya kullanılan thread sayısı üzerinde daha hassas bir denetim kurmak istiyorsanız, test ikili dosyasına --test-threads bayrağını ve kullanmak istediğiniz thread sayısını gönderebilirsiniz. Aşağıdaki örneğe göz atalım:

$ cargo test -- --test-threads=1

Test thread’i sayısını 1 olarak ayarlayarak programa hiçbir paralellik kullanmamasını söylüyoruz. Testleri tek bir thread üzerinden çalıştırmak paralel çalıştırmaya kıyasla daha uzun sürer; ancak ortak bir durumu paylaşsalar bile testler birbirleriyle çakışmaz.

Fonksiyon Çıktısını Gösterme

Varsayılan olarak bir test başarılı olduğunda, Rust’ın test kütüphanesi standart çıktıya yazdırılan her şeyi yakalar. Örneğin bir testin içinde println! çağırırsak ve test geçerse, terminalde println! çıktısını görmeyiz; yalnızca testin geçtiğini belirten satırı görürüz. Bir test başarısız olursa, standart çıktıya yazdırılan her şeyi hata mesajının geri kalanıyla birlikte görürüz.

Örnek olarak Liste 11-10’da, aldığı parametrenin değerini ekrana yazdırıp 10 döndüren basit bir fonksiyon ile biri geçen, diğeri başarısız olan iki test yer almaktadır.

Dosya adı: src/lib.rs
fn yazdir_ve_10_dondur(a: i32) -> i32 {
    println!("{a} değerini aldım");
    10
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn bu_test_gececek() {
        let deger = yazdir_ve_10_dondur(4);
        assert_eq!(deger, 10);
    }

    #[test]
    fn bu_test_basarisiz_olacak() {
        let deger = yazdir_ve_10_dondur(8);
        assert_eq!(deger, 5);
    }
}
Liste 11-10: println! çağıran bir fonksiyon için testler

Bu testleri cargo test ile çalıştırdığımızda aşağıdaki çıktıyı görürüz:

$ cargo test
   Compiling silly-function v0.1.0 (file:///projects/silly-function)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58s
     Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166)

running 2 tests
test tests::bu_test_basarisiz_olacak ... FAILED
test tests::bu_test_gececek ... ok

failures:

---- tests::bu_test_basarisiz_olacak stdout ----
8 değerini aldım

thread 'tests::bu_test_basarisiz_olacak' (6019863) panicked at src/lib.rs:19:9:
assertion `left == right` failed
  left: 10
 right: 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::bu_test_basarisiz_olacak

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

Bu çıktının hiçbir yerinde, geçen test çalıştırıldığında yazdırılan 4 değerini aldım ifadesini görmediğimize dikkat edin; bu çıktı yakalanmıştır. Başarısız olan testin ürettiği 8 değerini aldım çıktısı ise testin neden başarısız olduğunu da gösteren test özeti bölümünde yer alır.

Geçen testlerin yazdırdığı değerleri de görmek istiyorsak --show-output bayrağıyla Rust’a başarılı testlerin çıktısını da göstermesini söyleyebiliriz:

$ cargo test -- --show-output

Liste 11-10’daki testleri --show-output bayrağıyla yeniden çalıştırdığımızda aşağıdaki çıktıyı görürüz:

$ cargo test -- --show-output
   Compiling silly-function v0.1.0 (file:///projects/silly-function)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166)

running 2 tests
test tests::bu_test_basarisiz_olacak ... FAILED
test tests::bu_test_gececek ... ok

successes:

---- tests::bu_test_gececek stdout ----
4 değerini aldım


successes:
    tests::bu_test_gececek

failures:

---- tests::bu_test_basarisiz_olacak stdout ----
8 değerini aldım

thread 'tests::bu_test_basarisiz_olacak' (6022313) panicked at src/lib.rs:19:9:
assertion `left == right` failed
  left: 10
 right: 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::bu_test_basarisiz_olacak

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`

Testlerin Bir Alt Kümesini İsme Göre Çalıştırma

Kapsamlı bir test paketinin tamamını çalıştırmak bazen uzun sürebilir. Kodun belirli bir bölümü üzerinde çalışıyorsanız yalnızca o kodla ilgili testleri çalıştırmak isteyebilirsiniz. Çalıştırmak istediğiniz testlerin adını veya adlarını cargo test komutuna argüman olarak vererek hangi testlerin çalıştırılacağını seçebilirsiniz.

Testlerin bir alt kümesinin nasıl çalıştırılacağını göstermek için önce Liste 11-11’de görüldüğü gibi iki_ekle fonksiyonumuz için üç test oluşturalım ve hangilerini çalıştıracağımızı seçelim.

Dosya adı: src/lib.rs
pub fn iki_ekle(a: u64) -> u64 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn iki_ve_iki_ekle() {
        let sonuc = iki_ekle(2);
        assert_eq!(sonuc, 4);
    }

    #[test]
    fn uc_ve_iki_ekle() {
        let sonuc = iki_ekle(3);
        assert_eq!(sonuc, 5);
    }

    #[test]
    fn yuz() {
        let sonuc = iki_ekle(100);
        assert_eq!(sonuc, 102);
    }
}
Liste 11-11: Üç farklı isme sahip üç test

Daha önce gördüğümüz gibi testleri hiçbir argüman vermeden çalıştırırsak tüm testler paralel olarak çalışır:

$ cargo test
   Compiling toplayici v0.1.0 (file:///projects/toplayici)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62s
     Running unittests src/lib.rs (target/debug/deps/toplayici-ac13090f6eeacc92)

running 3 tests
test tests::uc_ve_iki_ekle ... ok
test tests::yuz ... ok
test tests::iki_ve_iki_ekle ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests toplayici

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Tek Bir Testi Çalıştırma

Yalnızca tek bir testi çalıştırmak için o test fonksiyonunun adını cargo test komutuna iletebiliriz:

$ cargo test yuz
   Compiling toplayici v0.1.0 (file:///projects/toplayici)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.69s
     Running unittests src/lib.rs (target/debug/deps/toplayici-ac13090f6eeacc92)

running 1 test
test tests::yuz ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s

Yalnızca yuz adlı test çalıştırıldı; diğer iki test bu isimle eşleşmedi. Test çıktısı, özet satırının sonunda 2 filtered out (2 test filtrelendi) ifadesini göstererek çalıştırılmayan başka testlerimiz de olduğunu bize bildirir.

Bu yöntemle birden fazla testin adını aynı anda belirleyemeyiz; cargo test komutuna verilen değerlerden yalnızca ilki kullanılır. Ancak birden fazla testi çalıştırmanın bir yolu vardır.

Birden Fazla Testi Çalıştırmak İçin Filtreleme

Bir test adının yalnızca bir kısmını belirtebiliriz; bu durumda adı belirtilen ifadeyi içeren tüm testler çalıştırılır. Örneğin testlerimizden ikisinin adı ekle içerdiğinden, cargo test ekle komutunu çalıştırarak bu iki testi yürütebiliriz:

$ cargo test ekle
   Compiling toplayici v0.1.0 (file:///projects/toplayici)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/toplayici-ac13090f6eeacc92)

running 2 tests
test tests::uc_ve_iki_ekle ... ok
test tests::iki_ve_iki_ekle ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s

Bu komut, adında ekle geçen tüm testleri çalıştırdı ve yuz adlı testi dışarıda bıraktı. Ayrıca bir testin içinde yer aldığı modülün de test adının bir parçası haline geldiğine dikkat edin (tests::yuz gibi); dolayısıyla modül adına göre filtreleme yaparak bir modüldeki tüm testleri çalıştırabiliriz.

Açıkça İstenmedikçe Testleri Yok Sayma

Bazen belirli birkaç testin çalışması çok uzun sürebilir; bu nedenle cargo test komutunun çoğu çalıştırmasında bunları kapsam dışı bırakmak isteyebilirsiniz. Çalıştırmak istediğiniz diğer tüm testleri tek tek argüman olarak listelemek yerine, burada gösterildiği gibi zaman alıcı testleri ignore özniteliğiyle işaretleyerek hariç tutabilirsiniz:

Dosya adı: src/lib.rs

pub fn topla(sol: u64, sag: u64) -> u64 {
    sol + sag
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn calisiyor() {
        let sonuc = topla(2, 2);
        assert_eq!(sonuc, 4);
    }

    #[test]
    #[ignore]
    fn pahali_test() {
        // çalışması bir saat süren kod
    }
}

#[test] satırından sonra, hariç tutmak istediğimiz teste #[ignore] satırını ekliyoruz. Artık testlerimizi çalıştırdığımızda calisiyor testi çalışır, ancak pahali_test çalışmaz:

$ cargo test
   Compiling toplayici v0.1.0 (file:///projects/toplayici)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running unittests src/lib.rs (target/debug/deps/toplayici-ac13090f6eeacc92)

running 2 tests
test tests::pahali_test ... ignored
test tests::calisiyor ... ok

test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests toplayici

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

pahali_test fonksiyonu çıktıda ignored (yok sayıldı) olarak listelenir. Yalnızca yok sayılan testleri çalıştırmak istersek cargo test -- --ignored komutunu kullanabiliriz:

$ cargo test -- --ignored
   Compiling toplayici v0.1.0 (file:///projects/toplayici)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/toplayici-ac13090f6eeacc92)

running 1 test
test tests::pahali_test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s

   Doc-tests toplayici

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Hangi testlerin çalıştırılacağını kontrol ederek cargo test sonuçlarınızın hızlıca dönmesini sağlayabilirsiniz. Yok sayılan testlerin sonuçlarını kontrol etmenin mantıklı olduğu bir aşamaya geldiğinizde ve sonuçları bekleyecek vaktiniz olduğunda cargo test -- --ignored komutunu çalıştırabilirsiniz. Yok sayılmış olsun ya da olmasın tüm testleri birlikte çalıştırmak isterseniz cargo test -- --include-ignored komutunu kullanabilirsiniz.