Rust
Test infrastructure
Add integration tests with the tests/ folder.
Test setup
We secure the library's behaviour with tests. Tests live in the same file, in a module compiled only during cargo test:
#[cfg(test)]
mod tests {
use super::kitaplik::*;
#[test]
fn arama_yazara_gore_bulur() {
let mut raf = Raf::new();
raf.ekle(Kitap::new("Tutunamayanlar", "Oğuz Atay", 1972));
assert_eq!(raf.ara("atay").len(), 1);
}
}
The #[cfg(test)] module isn't included in a normal build; use super::.. brings the parent module's items into scope.
What should be tested?
Good tests check the contract the user relies on: the constructor storing values correctly, the search working regardless of case, a query with no matches returning an empty result. Each test should cover a single behaviour and have a descriptive name:
#[test]
fn arama_buyuk_kucuk_harf_duyarsiz() { .. }
#[test]
fn bulunamayan_sorgu_bos_doner() {
let raf: Raf<Kitap> = Raf::new();
assert!(raf.ara("xyz").is_empty());
}
Exercise Tests and a check
Add #[cfg(test)] mod tests to the previous library code: write two #[test]s checking 2 results for ara("atay") with assert_eq! and an empty result for ara("xyz"). Since the exercise environment runs main, also do the same two checks with assert! in main and print tüm denetimler geçti.
Show example solution
mod kitaplik {
pub struct Kitap {
ad: String,
yazar: String,
yil: u16,
}
impl Kitap {
pub fn new(ad: &str, yazar: &str, yil: u16) -> Self {
Self {
ad: ad.to_string(),
yazar: yazar.to_string(),
yil,
}
}
pub fn ad(&self) -> &str {
&self.ad
}
pub fn yil(&self) -> u16 {
self.yil
}
}
pub struct Raf<T> {
ogeler: Vec<T>,
}
impl<T> Raf<T> {
pub fn new() -> Self {
Self { ogeler: Vec::new() }
}
pub fn ekle(&mut self, x: T) {
self.ogeler.push(x);
}
pub fn len(&self) -> usize {
self.ogeler.len()
}
}
pub trait Aranabilir {
fn eslesir(&self, sorgu: &str) -> bool;
}
impl Aranabilir for Kitap {
fn eslesir(&self, sorgu: &str) -> bool {
let s = sorgu.to_lowercase();
self.ad.to_lowercase().contains(&s) || self.yazar.to_lowercase().contains(&s)
}
}
impl<T: Aranabilir> Raf<T> {
pub fn ara(&self, sorgu: &str) -> Vec<&T> {
self.ogeler.iter().filter(|x| x.eslesir(sorgu)).collect()
}
}
}
use kitaplik::{Kitap, Raf};
fn ornek_raf() -> Raf<Kitap> {
let mut raf = Raf::new();
raf.ekle(Kitap::new("Tutunamayanlar", "Oğuz Atay", 1972));
raf.ekle(Kitap::new("Tehlikeli Oyunlar", "Oğuz Atay", 1973));
raf.ekle(Kitap::new("Kürk Mantolu Madonna", "Sabahattin Ali", 1943));
raf
}
fn main() {
let raf = ornek_raf();
assert!(raf.ara("atay").len() == 2);
assert!(raf.ara("xyz").is_empty());
println!("tüm denetimler geçti");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn yazara_gore_bulur() {
assert_eq!(ornek_raf().ara("atay").len(), 2);
}
#[test]
fn bulunamayan_bos_doner() {
assert!(ornek_raf().ara("xyz").is_empty());
}
}
Test yourself
-
What does <code>cargo test</code> do when a test fails?
- Stops immediately
- Skips the test
- Gives a compile error
- Keeps running the other tests and reports the failures at the end
Show answer
Keeps running the other tests and reports the failures at the end — Each test runs on its own thread; one test's panic doesn't affect the others.
-
Compile only in tests
#[____]
mod tests {
#[test]
fn ornek() {}
}
Show answer
#[cfg(test)]
mod tests {
#[test]
fn ornek() {}
}
-
Item and role
- #[cfg(test)]
- Conditional compilation
- #[test]
- Test function
- assert_eq!(a, b)
- Equality check
- use super::*
- Brings the parent into scope
Next lesson: Box<T>