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’ın kodunuzu derlemesi ve ardından ortaya çıkan ikili dosyayı çalıştırması gibi, cargo test de kodunuzu test modunda derler ve ortaya çıkan test ikili dosyasını çalıştırır. cargo test tarafından üretilen ikili dosyanın varsayılan davranışı, tüm testleri paralel olarak çalıştırmak ve test çalışmaları (test runs) sırasında üretilen çıktıyı yakalayarak çıktının görüntülenmesini engellemek ve test sonuçlarıyla ilgili çıktının okunmasını kolaylaştırmaktır. Ancak bu varsayılan davranışı değiştirmek için komut satırı seçeneklerini (command line options) belirtebilirsiniz.

Bazı komut satırı seçenekleri cargo test’e, bazıları ise ortaya çıkan test ikili dosyasına gider. Bu iki tür argümanı ayırmak için cargo test’e giden argümanları, ardından -- ayırıcısını (separator) ve ardından test ikili dosyasına gidenleri listelersiniz. cargo test --help komutunu çalıştırmak cargo test ile kullanabileceğiniz seçenekleri gösterirken, cargo test -- --help komutunu çalıştırmak ayırıcıdan sonra kullanabileceğiniz seçenekleri gösterir. Bu seçenekler aynı zamanda rustc Kitabının “Testler” (Tests) bölümünde de belgelenmiştir.

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

Birden fazla test çalıştırdığınızda, varsayılan olarak bunlar iş parçacıklarını kullanarak paralel olarak çalışır, yani daha çabuk bitirirler ve daha çabuk geri bildirim alırsınız. Testler aynı anda çalıştığı için testlerinizin birbirine ya da geçerli çalışma dizini veya çevre değişkenleri (environment variables) gibi paylaşılan bir çevre de dahil olmak üzere paylaşılan herhangi bir duruma (shared state) bağlı olmadığından emin olmalısınız.

Örneğin, testlerinizin her birinin diskte test-ciktisi.txt (test-output.txt) adında bir dosya oluşturan ve bu dosyaya bir miktar veri yazan bir kod çalıştırdığını varsayalım. Ardından her test bu dosyadaki verileri okur ve dosyanın belirli bir değer içerdiğini (her testte farklı olan) doğrular. Testler aynı anda çalıştığı için bir test dosyayı yazıp okuduğu sırada başka bir test dosyanın üzerine yazabilir (overwrite). İkinci test daha sonra kod yanlış olduğu için değil, paralel çalışırken testler birbirine karıştığı (interfered) için başarısız olacaktır. Çözümlerden biri her testin farklı bir dosyaya yazdığından emin olmaktır; başka bir çözüm de testleri teker teker (one at a time) çalıştırmaktır.

Eğer testleri paralel çalıştırmak istemiyorsanız ya da kullanılan iş parçacığı sayısı üzerinde daha ince taneli bir kontrole (fine-grained control) sahip olmak istiyorsanız --test-threads bayrağını (flag) ve kullanmak istediğiniz iş parçacığı sayısını test ikili dosyasına gönderebilirsiniz. Aşağıdaki örneğe bir göz atın:

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

Test iş parçacığı sayısını 1 olarak ayarlayarak programa herhangi bir paralellik kullanmamasını söylüyoruz. Testleri tek bir iş parçacığı kullanarak çalıştırmak, paralel olarak çalıştırmaktan daha uzun sürecektir ancak durumu (state) paylaşmaları halinde testler birbirine karışmayacaktır.

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

Varsayılan olarak, bir test geçerse Rust’ın test kütüphanesi standart çıktıya (standard output) yazdırılan her şeyi yakalar. Örneğin bir testte println! çağırırsak ve test geçerse, println! çıktısını terminalde görmeyiz; sadece testin geçtiğini gösteren satırı görürüz. Bir test başarısız olursa, standart çıktıya yazdırılan her şeyi başarısızlık mesajının geri kalanıyla birlikte göreceğiz.

Buna bir örnek olarak Liste 11-10’da, parametresinin değerini yazdıran ve 10 döndüren anlamsız (silly) bir fonksiyonun yanı sıra geçen bir test ve başarısız olan bir test bulunmaktadır.

Filename: src/lib.rs
fn yazdir_ve_10_dondur(a: i32) -> i32 {
    println!("{} değerini aldım", a);
    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);
    }
}
Listing 11-10: println! çağıran bir fonksiyon için testler

Bu testleri cargo test ile çalıştırdığımızda şu çıktıyı göreceğiz:

$ 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' 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`

Unutmayın ki geçen test çalıştığında ekrana yazdırılan 4 değerini aldım (I got the value 4) ifadesini bu çıktının hiçbir yerinde göremiyoruz. Bu çıktı yakalanmıştır. Başarısız olan testten gelen 8 değerini aldım (I got the value 8) çıktısı, test başarısızlığının nedenini de gösteren test özeti çıktısının bölümünde yer alıyor.

Eğer geçen testlerin yazdırılan değerlerini de görmek istiyorsak Rust’a --show-output ile başarılı testlerin çıktısını da göstermesini söyleyebiliriz:

$ cargo test -- --show-output

Liste 11-10’daki testleri --show-output bayrağı ile tekrar ç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' 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ırmak

Tam bir test paketini (test suite) çalıştırmak bazen uzun sürebilir. Eğer belirli bir alandaki kod üzerinde çalışıyorsanız sadece o kodla ilgili testleri çalıştırmak isteyebilirsiniz. Çalıştırmak istediğiniz test(ler)in adını veya adlarını argüman olarak cargo test’e ileterek hangi testlerin çalıştırılacağını seçebilirsiniz.

Testlerin bir alt kümesinin (subset) nasıl çalıştırılacağını göstermek için öncelikle Liste 11-11’de gösterildiği gibi iki_ekle fonksiyonumuz için üç test oluşturacak ve hangilerinin çalıştırılacağını seçeceğiz.

Filename: 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);
    }
}
Listing 11-11: Üç farklı isme sahip üç test

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

$ cargo test
   Compiling toplayici v0.1.0 ($PROJE/listings/ch11-writing-automated-tests/listing-11-11)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     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ırmak

Sadece o testi çalıştırmak için herhangi bir test fonksiyonunun adını cargo test’e geçebiliriz:

$ cargo test yuz
   Compiling toplayici v0.1.0 ($PROJE/listings/ch11-writing-automated-tests/output-only-02-single-test)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     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

Sadece yuz (one_hundred) isimli test çalıştırıldı; diğer iki test bu isme uymadı. Test çıktısı, sonunda 2 filtered out (2 filtrelendi) görüntüleyerek, çalışmayan daha fazla testimiz olduğunu bize bildirir.

Bu şekilde birden fazla testin adını belirleyemeyiz; yalnızca cargo test’e verilen ilk değer kullanılacaktır. Ancak birden fazla test çalıştırmanın bir yolu var.

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

Bir test adının bir bölümünü belirtebiliriz ve adı bu değerle eşleşen tüm testler çalıştırılır. Örneğin testlerimizden ikisinin adı ekle içerdiğinden cargo test ekle komutunu kullanarak bu ikisini çalıştırabiliriz:

$ cargo test ekle
   Compiling toplayici v0.1.0 ($PROJE/listings/ch11-writing-automated-tests/output-only-03-multiple-tests)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     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 olan tüm testleri çalıştırdı ve yuz (one_hundred) adlı testi filtreledi. Ayrıca bir testin içinde göründüğü modülün testin adının bir parçası haline geldiğini, dolayısıyla modülün adına göre filtreleme yaparak bir modüldeki tüm testleri çalıştırabileceğimizi unutmayın.

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

Bazen birkaç spesifik testin çalıştırılması çok zaman alıcı (time-consuming) olabilir, bu nedenle cargo test’in çoğu çalıştırması sırasında bunları hariç tutmak isteyebilirsiniz. Çalıştırmak istediğiniz tüm testleri argüman olarak listelemek yerine zaman alan testleri dışarıda bırakmak için Liste 11-12’de gösterildiği gibi ignore (yoksay) özniteliğini (attribute) kullanarak onlara açıklama ekleyebilirsiniz:

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]’ten sonra, hariç tutmak istediğimiz teste #[ignore] satırını ekleriz. Artık testlerimizi çalıştırdığımızda calisiyor çalışıyor ancak pahali_test (expensive_test) çalışmıyor:

$ cargo test
   Compiling toplayici v0.1.0 ($PROJE/listings/ch11-writing-automated-tests/no-listing-11-ignore-a-test)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     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 ignored (yoksayıldı) olarak listelenir. Sadece yoksayılan testleri çalıştırmak istiyorsak cargo test -- --ignored komutunu kullanabiliriz:

$ cargo test -- --ignored
   Compiling toplayici v0.1.0 ($PROJE/listings/ch11-writing-automated-tests/output-only-04-running-ignored)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.11s
     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ı bir şekilde dönmesini sağlayabilirsiniz. ignored (yoksayılan) testlerin sonuçlarını kontrol etmenin mantıklı olduğu bir noktaya geldiğinizde ve sonuçları beklemek için zamanınız olduğunda bunun yerine cargo test -- --ignored çalıştırabilirsiniz. İster yoksayılsın ister yoksayılmasın tüm testleri çalıştırmak istiyorsanız cargo test -- --include-ignored komutunu çalıştırabilirsiniz.