最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Rust編寫(xiě)自動(dòng)化測(cè)試實(shí)例權(quán)威指南

 更新時(shí)間:2022年12月05日 15:35:00   作者:麒麟閣  
這篇文章主要為大家介紹了Rust編寫(xiě)自動(dòng)化測(cè)試實(shí)例權(quán)威指南詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一. 簡(jiǎn)述

雖然Rust的類型系統(tǒng)為我們提供了相當(dāng)多的安全保障,但是還是不足以防止所有的錯(cuò)誤。因此,Rust在語(yǔ)言層面內(nèi)置了編寫(xiě)測(cè)試代碼、執(zhí)行自動(dòng)化測(cè)試任務(wù)的功能。

測(cè)試是一門(mén)復(fù)雜的技術(shù),本章覆蓋關(guān)于如何編寫(xiě)優(yōu)秀測(cè)試的每一個(gè)細(xì)節(jié),但是會(huì)討論Rust測(cè)試工具的運(yùn)行機(jī)制。我們會(huì)向你介紹編寫(xiě)測(cè)試時(shí)常用的標(biāo)注和宏、運(yùn)行測(cè)試的默認(rèn)行為和選項(xiàng)參數(shù),以及如何將測(cè)試用例組織為單元測(cè)試與集成測(cè)試。

二. 編寫(xiě)測(cè)試

Rust語(yǔ)言中的測(cè)試時(shí)一個(gè)函數(shù),它被用于驗(yàn)證非測(cè)試代碼是否按照期望的方式運(yùn)行。測(cè)試函數(shù)的函數(shù)體中一般包含3個(gè)部分:

  • 準(zhǔn)備所需的數(shù)據(jù)或狀態(tài)
  • 調(diào)用需要測(cè)試的代碼
  • 斷言運(yùn)行結(jié)果與我們期望的一致

接下來(lái),我們會(huì)一起學(xué)習(xí)用于編寫(xiě)測(cè)試代碼的相關(guān)功能,它們包含test屬性、一些測(cè)試宏及should_panic屬性。此時(shí)我們將建一個(gè)庫(kù)項(xiàng)目:cargo new adder —lib

此時(shí)adder庫(kù)項(xiàng)目自動(dòng)生成一個(gè)src/lib.rs文件,此時(shí)cargo會(huì)給我們創(chuàng)建一個(gè)簡(jiǎn)單的測(cè)試代碼模塊:

pub fn add(left: usize, right: usize) -> usize {
    left + right
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test] // @1
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4); // @2
    }
}

我們可以看到@1這一行的#[test]標(biāo)注:它將當(dāng)前的函數(shù)標(biāo)記為一個(gè)測(cè)試,并使該函數(shù)可以在測(cè)試運(yùn)行中被識(shí)別出來(lái)。要知道,即便是在tests模塊中也可能會(huì)存在普通的非測(cè)試函數(shù),它們通常被用來(lái)執(zhí)行初始化操作或一些常用指令,所以我們必須要將測(cè)試函數(shù)標(biāo)注為#[test]。函數(shù)體中@2使用了assert_eq!宏斷言,這是一個(gè)典型的測(cè)試用例編寫(xiě)方式。這時(shí)我們執(zhí)行命令:cargo test

xxxxx@xxxxxx adder % cargo test
   Compiling adder v0.1.0 (/rust-example/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.05s
     Running unittests src/lib.rs (target/debug/deps/adder-96bda0c2404f749c)
running 1 test  // 正在執(zhí)行一個(gè)測(cè)試
test tests::it_works ... ok // 此時(shí)函數(shù)
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s // 測(cè)試摘要,表示該集合中的所有測(cè)試均成功通過(guò),1 passed; 0 failed則統(tǒng)計(jì)了通過(guò)和失敗的測(cè)試總數(shù)
   Doc-tests adder // 文件測(cè)試的結(jié)果
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

此時(shí)我們刪除初始化的代碼,我們編寫(xiě)下面兩個(gè)測(cè)試函數(shù):

extern crate core;
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn ok_test() {
        assert_eq!(2 + 2, 4);
    }
    #[test]
    fn fail_test() {
        panic!("Make this test fail");
    }
}

此時(shí)我們?cè)俅螆?zhí)行cargo test運(yùn)行測(cè)試!可預(yù)見(jiàn)的ok_test肯定是OK的,fail_test我們?cè)诶锩鎸?xiě)了panic!測(cè)試失??!

xxxxxx@xxxxxx adder % cargo test
   Compiling adder v0.1.0 (/rust-example/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.13s
     Running unittests src/lib.rs (target/debug/deps/adder-96bda0c2404f749c)
running 2 tests
test tests::ok_test ... ok
test tests::fail_test ... FAILED
failures:
---- tests::fail_test stdout ----
thread 'tests::fail_test' panicked at 'Make this test fail', src/lib.rs:11:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
    tests::fail_test
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`

測(cè)試信息輸出非常明顯,測(cè)試失敗的位置提示很明確。

三. 測(cè)試相關(guān)的宏和函數(shù)

下面我們介紹一些我們?cè)诰帉?xiě)測(cè)試時(shí)會(huì)使用到的相關(guān)宏和方法!

3.1. 使用assert!宏檢查結(jié)果

assert!宏由標(biāo)準(zhǔn)庫(kù)提供,它可以確保測(cè)試中某些條件的值是trueassert!宏可以接收一個(gè)能夠被計(jì)算為布爾類型的值作為參數(shù)。當(dāng)這個(gè)值為true時(shí),assert!宏什么都不做并正常通過(guò)測(cè)試。而當(dāng)值時(shí)false時(shí),assert!宏就會(huì)調(diào)用panic!宏,進(jìn)而導(dǎo)致測(cè)試失敗。使用assert!宏可以檢查代碼是否按照我們預(yù)期的方式運(yùn)行。

#[derive(Debug)]
pub struct Rectangle {
    length: u32,
    width: u32,
}
impl Rectangle {
    pub fn can_hold(&self, other: &Rectangle) -> bool {
        self.length > other.length && self.width > other.width
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle { length: 9, width: 7 };
        let smaller = Rectangle { length: 5, width: 1 };
        assert!(larger.can_hold(&smaller));
    }
    #[test]
    fn smaller_cannot_hold_larger() {
        let larger = Rectangle { length: 9, width: 7 };
        let smaller = Rectangle { length: 5, width: 1 };
        assert!(smaller.can_hold(&larger)); // fasle, 斷言失敗
    }
}

此時(shí)執(zhí)行cargo test測(cè)試代碼:一個(gè)成功,一個(gè)失敗。

xxxxx@xxxxxxx adder % cargo test
   Compiling adder v0.1.0 (/rust-example/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.12s
     Running unittests src/lib.rs (target/debug/deps/adder-96bda0c2404f749c)
running 2 tests
test tests::larger_can_hold_smaller ... ok
test tests::smaller_cannot_hold_larger ... FAILED
failures:
---- tests::smaller_cannot_hold_larger stdout ----
thread 'tests::smaller_cannot_hold_larger' panicked at 'assertion failed: smaller.can_hold(&larger)', src/lib.rs:29:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
    tests::smaller_cannot_hold_larger
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`

3.2. 使用assert_eq!宏和assert_ne!宏判斷相等性

在對(duì)功能進(jìn)行測(cè)試時(shí),我們常常需要將被測(cè)試代碼的結(jié)果與我們所期望的結(jié)果相比較,并檢查它們是否相等。在標(biāo)準(zhǔn)庫(kù)中提供了一對(duì)可以簡(jiǎn)化編程的宏:assert_eq!assert_ne!。這兩個(gè)宏分別用于比較并斷言兩個(gè)參數(shù)相等或不相等。在斷言失敗時(shí),它們還可以自動(dòng)打印出兩個(gè)參數(shù)的值,從而方便我們觀察測(cè)試失敗的原因;相反,使用assert!宏則只能得知==判斷表達(dá)式失敗的事實(shí),而無(wú)法知曉用于比較的值。

pub fn add_two(a: i32) -> i32 {
    a + 2
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn ok_adds_two_eq() {
        // 斷言結(jié)果相同測(cè)試通過(guò)
        assert_eq!(4, add_two(2));
    }
    #[test]
    fn fail_adds_two_eq() {
        // 斷言結(jié)果不相同觸發(fā)panic
        assert_eq!(5, add_two(2));
    }
    #[test]
    fn ok_adds_two_ne() {
        // 斷言結(jié)果不一致測(cè)試通過(guò)
        assert_ne!(5, add_two(2));
    }
    #[test]
    fn fail_adds_two_ne() {
        // 斷言結(jié)果相同觸發(fā)panic
        assert_ne!(4, add_two(2));
    }
}

執(zhí)行測(cè)試代碼:

yuelong@yuelongdeMBP adder % cargo test
   Compiling adder v0.1.0 (/Users/yuelong/CodeHome/TestProject/rust-example/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.12s
     Running unittests src/lib.rs (target/debug/deps/adder-96bda0c2404f749c)
running 4 tests
test tests::ok_adds_two_ne ... ok
test tests::ok_adds_two_eq ... ok
test tests::fail_adds_two_eq ... FAILED
test tests::fail_adds_two_ne ... FAILED
failures:
---- tests::fail_adds_two_eq stdout ----
thread 'tests::fail_adds_two_eq' panicked at 'assertion failed: `(left == right)`
  left: `5`,
 right: `4`', src/lib.rs:16:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
---- tests::fail_adds_two_ne stdout ----
thread 'tests::fail_adds_two_ne' panicked at 'assertion failed: `(left != right)`
  left: `4`,
 right: `4`', src/lib.rs:26:9
failures:
    tests::fail_adds_two_eq
    tests::fail_adds_two_ne
test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass `--lib`

測(cè)試順利通過(guò)檢查。

3.3. 添加自定義的錯(cuò)誤提示信息

我們也可以添加自定義的錯(cuò)誤提示信息,將其作為可選的參數(shù)傳入assert!、assert_eq!assert_ne!宏。實(shí)際上面任何在assert!、assert_eq!assert_ne!的必要參數(shù)之后出現(xiàn)的參數(shù)都會(huì)一起被傳遞給format!宏。因此,你甚至可以將一個(gè)包含{}占位符的格式化字符串及相對(duì)應(yīng)的填充值作為參數(shù)一起傳遞給這個(gè)宏。自定義的錯(cuò)誤提示信息可以很方便地記錄當(dāng)前斷言的含義;這樣在測(cè)試失敗時(shí),我們就可以更容易的知道代碼到底出了什么問(wèn)題。

pub fn greeting(name: &str) -> String {
    String::from("Hello!")
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn greeting_test() {
        let result = greeting("Carol");
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{}`", result
        )
    }
}

當(dāng)測(cè)試失敗之后:

running 1 test
test tests::greeting_test ... FAILED
failures:
---- tests::greeting_test stdout ----
thread 'tests::greeting_test' panicked at 'Greeting did not contain name, value was `Hello!`', src/lib.rs:16:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
    tests::greeting_test
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

這次的測(cè)試輸出中包含了實(shí)際的值,他能幫助我們觀察程序真正發(fā)生的行為,并迅速定位與預(yù)期產(chǎn)生差異的地方。

3.4. 使用should_panic檢查paninc

除了檢查代碼是否返回了正確的結(jié)果,確認(rèn)代碼能否按照預(yù)期處理錯(cuò)誤狀態(tài)同樣重要。

pub struct Guess {
    value: u32,
}
impl Guess {
    pub fn new(value: u32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }
        Guess { value }
    }
    pub fn new_plus(value: u32) -> Guess {
        if value < 1 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }
        Guess { value }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    #[should_panic]
    fn new_test() {
        // 此時(shí)肯定會(huì)發(fā)生錯(cuò)誤, 但是因?yàn)榧恿藄hould_panic宏,所有測(cè)試通過(guò)
        Guess::new(200);
    }
    #[test]
    #[should_panic]
    fn new_plus_test() {
        // 此時(shí)不會(huì)發(fā)生錯(cuò)誤, 但是因?yàn)榧恿藄hould_panic宏,所有測(cè)試無(wú)法通過(guò)
        Guess::new(200);
    }
}

執(zhí)行cargo test并不會(huì)失敗:

running 2 tests
test tests::new_plus_test - should panic ... FAILED
test tests::new_test - should panic ... ok
failures:
---- tests::new_plus_test stdout ----
note: test did not panic as expected
failures:
    tests::new_plus_test
test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

使用should_panic進(jìn)行的測(cè)試可能會(huì)有些模糊不清,因?yàn)樗麄儍H僅能夠說(shuō)明被檢查的代碼會(huì)發(fā)生panic。即便函數(shù)發(fā)生panic的原因和我們預(yù)期的不同,使用should_panic進(jìn)行測(cè)試也會(huì)順利通過(guò)。為了讓should_panic測(cè)試更加精確一些,我們可以在should_panic屬性中添加可選參數(shù)expected。它會(huì)檢查panic發(fā)生時(shí)輸出的錯(cuò)誤提示信息是否包含了指定的文字。例子:

pub struct Guess {
    value: u32,
}
impl Guess {
    pub fn new(value: u32) -> Guess {
        if value < 1 {
            panic!("Guess value must be greater than or equal to 1, got {}.", value);
        } else if value > 100 {
            panic!("Guess value must be less than or equal to 100, got {}.", value);
        } else {
            Guess { value }
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    #[should_panic(expected = "Guess value must be less than or equal to 100")]
    fn new_test() {
        // 此時(shí)肯定會(huì)發(fā)生錯(cuò)誤
        Guess::new(0);
    }
}

此時(shí)再次執(zhí)行測(cè)試:

running 1 test
test tests::new_test - should panic ... FAILED
failures:
---- tests::new_test stdout ----
thread 'tests::new_test' panicked at 'Guess value must be greater than or equal to 1, got 0.', src/lib.rs:8:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: panic did not contain expected string
      panic message: `"Guess value must be greater than or equal to 1, got 0."`,
 expected substring: `"Guess value must be less than or equal to 100"`
failures:
    tests::new_test
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

3.5. 使用Result<T, E>編寫(xiě)測(cè)試

到目前為止,我們編寫(xiě)的測(cè)試都會(huì)在運(yùn)行失敗時(shí)觸發(fā)panic。不過(guò)我們也可以用Result<T, E>來(lái)編寫(xiě)測(cè)試!例子:

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn new_test() -> Result<(), String> {
        if 2 + 2 == 4 {
            Ok(())
        } else {
            Err(String::from("two plus two does not equal four"))
        }
    }
}

在函數(shù)體中,我們不再調(diào)用assert_eq!宏,而是在測(cè)試的時(shí)候通過(guò)時(shí)返回Ok(()),在失敗時(shí)返回一個(gè)帶有StringErr值。

不要在使用Reuslt<T, E>編寫(xiě)的測(cè)試上標(biāo)注#[should_panic]。在測(cè)試失敗時(shí),我們應(yīng)該直接返回一個(gè)Err值。

四. 控制測(cè)試的運(yùn)行方式

如同cargo run會(huì)編譯代碼并運(yùn)行生成的二進(jìn)制文件一樣,cargo test同樣會(huì)在測(cè)試環(huán)境下編譯代碼,并運(yùn)行生成的測(cè)試二進(jìn)制文件。你可以通過(guò)指定命令行參數(shù)來(lái)改變cargo test的默認(rèn)行為。

cargo test --help // 查看cargo test的可用參數(shù)
cargo test -- --help // 顯示出所有可用在 -- 之后的參數(shù)

4.1. 并行或串行的進(jìn)行測(cè)試

當(dāng)我們嘗試運(yùn)行多個(gè)測(cè)試,Rust會(huì)默認(rèn)使用多線程來(lái)執(zhí)行它們。這樣可以讓測(cè)試更快地運(yùn)行完畢。從來(lái)盡早得到代碼是否可以正常工作的反饋。但是由于測(cè)試是同時(shí)進(jìn)行的,所以開(kāi)發(fā)者必須保證測(cè)試之間不會(huì)互相依賴,或者依賴到同一個(gè)共享的狀態(tài)或環(huán)境上,例如當(dāng)前工作目錄、環(huán)境變量等。

如果你不想必行運(yùn)行測(cè)試,或者希望精確的控制測(cè)試時(shí)所啟動(dòng)的線程數(shù)量,那么可以通過(guò)給測(cè)試二進(jìn)制文件傳入 —test-threads標(biāo)記及期望的具體線程數(shù)量來(lái)控制這一行為。

cargo test -- --test-threads=1 // 將線程數(shù)量控制為1,這也意味著程序不會(huì)使用任何并行操作,使用單線程執(zhí)行測(cè)試會(huì)比并行話費(fèi)更多的時(shí)間,但是順序執(zhí)行不會(huì)再因?yàn)楣蚕頎顟B(tài)而出現(xiàn)可能的干擾情形了

4.2. 顯示函數(shù)輸出

默認(rèn)情況下,Rust的測(cè)試庫(kù)會(huì)在測(cè)試通過(guò)時(shí)捕獲所有被打印至標(biāo)準(zhǔn)輸出中的消息。當(dāng)我們測(cè)試通過(guò),它所打印的內(nèi)容就無(wú)法顯示在終端上;我們只能看到一條用于指明測(cè)試通過(guò)的消息。只有在測(cè)試失敗時(shí),我么你才能在錯(cuò)誤提示信息的上方觀察到打印至標(biāo)準(zhǔn)輸出中的內(nèi)容。例子:

pub fn add(x: i32, y: i32) -> i32 {
    println!("x => {}, y => {}", x, y); // @1
    x + y
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn new_test() {
        assert_eq!(4, add(2, 2))
    }
}

我們希望在測(cè)試通過(guò)時(shí)也將值打印出來(lái),那么可以傳入—nocapture標(biāo)記來(lái)禁用輸出截獲功能,執(zhí)行下面的命令比較輸出結(jié)果:

cargo test -- --nocapture  // 會(huì)將@1也輸出顯示
cargo test                 // 沒(méi)有輸出@1

4.3. 只運(yùn)行部分特定名稱的測(cè)試

執(zhí)行全部的測(cè)試用例有時(shí)會(huì)花費(fèi)很長(zhǎng)時(shí)間。而在編寫(xiě)某個(gè)特定部分的代碼時(shí),你也許只需要運(yùn)行和代碼相對(duì)應(yīng)地那部分測(cè)試。我們可以通過(guò)cargo test中傳遞測(cè)試名稱來(lái)指定需要運(yùn)行的測(cè)試。例子:

pub fn add(x: i32, y: i32) -> i32 {
    println!("x => {}, y => {}", x, y);
    x + y
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn new_test() {
        assert_eq!(4, add(2, 2))
    }
    #[test]
    fn new_test_1() {
        assert_eq!(5, add(2, 2))
    }
    #[test]
    fn test_1() {
        assert_eq!(6, add(2, 2))
    }
}

這時(shí)我們可以指定測(cè)試名稱進(jìn)行單獨(dú)測(cè)試:

cargo test new_test_1

另外我們可以使用名稱過(guò)濾運(yùn)行多個(gè)測(cè)試:

cargo test new // 此時(shí)就會(huì)匹配到 new_test 和 new_test_1這兩個(gè)測(cè)試

4.4. 通過(guò)顯示指定來(lái)忽略某些測(cè)試

有時(shí),一些特定的測(cè)試執(zhí)行起來(lái)會(huì)非常耗時(shí),所有你可能會(huì)想要在大部分的cargo test命令中忽略它們。除了手動(dòng)將想要運(yùn)行的測(cè)試列舉出來(lái),我們也可以使用ignore屬性來(lái)標(biāo)記這些耗時(shí)的測(cè)試,將這些測(cè)試排除在正常的測(cè)試運(yùn)行之外。

pub fn add(x: i32, y: i32) -> i32 {
    println!("x => {}, y => {}", x, y);
    x + y
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn new_test_1() {
        assert_eq!(5, add(2, 2))
    }
    #[test]
    #[ignore]
    fn test_1() {
        assert_eq!(6, add(2, 2))
    }
}

此時(shí)我們執(zhí)行cargo test時(shí)就可以很明顯的看到ignored的標(biāo)識(shí):

xxxxxx@xxxxxxx adder % cargo test 
    Finished test [unoptimized + debuginfo] target(s) in 0.00s
     Running unittests src/lib.rs (target/debug/deps/adder-96bda0c2404f749c)
running 3 tests
test tests::test_1 ... ignored
test tests::new_test ... ok
test tests::new_test_1 ... FAILED

此時(shí)我們也可以使用cargo test —- —-ignored來(lái)單獨(dú)運(yùn)行這些被忽略的測(cè)試。

xxxxx@xxxxxx adder % cargo test -- --ignored
    Finished test [unoptimized + debuginfo] target(s) in 0.00s
     Running unittests src/lib.rs (target/debug/deps/adder-96bda0c2404f749c)
running 1 test
test tests::test_1 ... FAILED
failures:
---- tests::test_1 stdout ----

五. 測(cè)試的組織結(jié)構(gòu)

Rust社區(qū)主要從以下兩個(gè)分類來(lái)討論測(cè)試:?jiǎn)卧獪y(cè)試(unit test)和集成測(cè)試(integration test)。單元測(cè)試小而專注,每次只單獨(dú)測(cè)試一個(gè)模塊或私有接口。而集成測(cè)試完全位于代碼庫(kù)之外,和正常從外部調(diào)用代碼一樣使用外部代碼,只能訪問(wèn)公共接口,而且再一次測(cè)試中可能會(huì)聯(lián)用多個(gè)模塊。

5.1. 單元測(cè)試

單元測(cè)試的目的在于將一小段代碼單獨(dú)隔離出來(lái),從而迅速確定這段代碼的功能是否符合預(yù)期。我們一般將單元測(cè)試與需要測(cè)試的代碼存放在src目錄下的同一文件中。同時(shí)也約定俗稱地在每個(gè)源代碼文件中都新建一個(gè)tests模塊來(lái)存放測(cè)試函數(shù),并使用cfg(test)對(duì)該模塊進(jìn)行標(biāo)注。

tests模塊上標(biāo)注#[cfg(test)]可以讓Rust只在執(zhí)行cargo test命令時(shí)編譯和運(yùn)行該部分測(cè)試代碼,而在執(zhí)行cargo build時(shí)剔除它們。這樣就可以在正常編譯時(shí)不包含測(cè)試代碼,從而節(jié)省編譯時(shí)間和產(chǎn)出物所占用的空間。我們不需要對(duì)集成測(cè)試標(biāo)注#[cfg(test)],因此集成測(cè)試本省就放置在獨(dú)立的目錄中。但是,由于本身測(cè)試是和業(yè)務(wù)代碼并列放置在同一文件中,所有我們必須使用#[cfg(test)]進(jìn)行標(biāo)注才能將單元測(cè)試的代碼排除在編譯產(chǎn)出物之外。Rust是允許測(cè)試私有函數(shù),例子:

// 共有函數(shù)
pub fn add(x: i32, y: i32) -> i32 { x + y }
// 私有函數(shù)
fn sub(x: i32, y: i32) -> i32 { x - y }
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn add_test() {
        assert_eq!(4, add(2, 2))
    }
    #[test]
    fn sub_test() {
        assert_eq!(0, sub(2, 2))
    }
}

5.2. 集成測(cè)試

Rust中,集成測(cè)試是完全位于代碼庫(kù)之外的。集成個(gè)測(cè)試調(diào)用庫(kù)的方式和其他的代碼調(diào)用方式?jīng)]有任何不同,這也意味著你只能調(diào)用對(duì)外公開(kāi)提供的那部分接口。集成測(cè)試的目的在于驗(yàn)證庫(kù)的不同部分能否協(xié)同起來(lái)工作。能夠獨(dú)立對(duì)外公開(kāi)提供的那部分接口。集成測(cè)試的目的在于驗(yàn)證庫(kù)的不同部分能否協(xié)同起來(lái)正常工作。能夠獨(dú)立正常工作的單元代碼的集成運(yùn)行時(shí)也會(huì)發(fā)生各種問(wèn)題,所有集成測(cè)試的覆蓋同樣是非常重要的。

為了創(chuàng)建集成測(cè)試,我們需要首先建立一個(gè)tests目錄。tests是文件夾和src文件夾并列。Cargo會(huì)自動(dòng)在這個(gè)目錄下尋找集成測(cè)試文件。在這個(gè)目錄下創(chuàng)建任意多個(gè)測(cè)試文件,Cargo在編譯時(shí)會(huì)將每個(gè)文件都處理為一個(gè)獨(dú)立的包。

我們?cè)趫?zhí)行cargo test

xxxxxx@xxxxxxx adder % cargo test
   Compiling adder v0.1.0 (/rust-example/adder)
    Finished test [unoptimized + debuginfo] target(s) in 0.15s
     Running unittests src/lib.rs (target/debug/deps/adder-96bda0c2404f749c)
running 1 test
test tests::add_test ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
     Running tests/adder_test.rs (target/debug/deps/adder_test-4bc3058753e422c8). // 執(zhí)行集成測(cè)試
running 1 test
test it_adds_two ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
   Doc-tests adder
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

如果此時(shí)有多個(gè)測(cè)試函數(shù),我們可以指定函數(shù)名,單獨(dú)運(yùn)行特定的集成測(cè)試函數(shù):

cargo test --test add_test

隨著集成測(cè)試增加,我們可以把tests目錄下的代碼分離到多個(gè)文件中。將每個(gè)集成測(cè)試的文件編譯成獨(dú)立的包有助于隔離作用域,并使集成測(cè)試環(huán)境更加貼近于用戶的使用場(chǎng)景。

但是在tests目錄中添加模塊并不是簡(jiǎn)單的添加一個(gè)文件,如圖:

接著我們就可以在測(cè)試函數(shù)中引用了

mod common; // 引入模塊
use adder;
#[test]
fn it_adds_two() {
    common::setup(); // 調(diào)用
    assert_eq!(4, adder::add(2, 2))
}

最后需要注意一點(diǎn),如果我們的項(xiàng)目是一個(gè)只有src/main.rs文件而沒(méi)有src/lib.rs文件的二進(jìn)制包,那么我們就無(wú)法在tests目錄中創(chuàng)建集成測(cè)試,也無(wú)法使用過(guò)usesrc/main.rs中定義的函數(shù)導(dǎo)入作用域。只有代碼包(library crate)才可以將函數(shù)暴露給其他包調(diào)用,而二進(jìn)制包只被用于獨(dú)立執(zhí)行。

以上就是Rust編寫(xiě)自動(dòng)化測(cè)試實(shí)例權(quán)威指南的詳細(xì)內(nèi)容,更多關(guān)于Rust編寫(xiě)自動(dòng)化測(cè)試的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Rust語(yǔ)言數(shù)據(jù)類型的具體使用

    Rust語(yǔ)言數(shù)據(jù)類型的具體使用

    在Rust中,每個(gè)值都有一個(gè)明確的數(shù)據(jù)類型,本文主要介紹了Rust語(yǔ)言數(shù)據(jù)類型的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-04-04
  • 從迷你todo?命令行入門(mén)Rust示例詳解

    從迷你todo?命令行入門(mén)Rust示例詳解

    這篇文章主要為大家介紹了從一個(gè)迷你todo命令行入門(mén)Rust的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Rust實(shí)現(xiàn)冒泡排序算法示例詳解

    Rust實(shí)現(xiàn)冒泡排序算法示例詳解

    這篇文章主要為大家介紹了Rust實(shí)現(xiàn)冒泡排序算法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Rust語(yǔ)言中的String和HashMap使用示例詳解

    Rust語(yǔ)言中的String和HashMap使用示例詳解

    這篇文章主要介紹了Rust語(yǔ)言中的String和HashMap使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 2022最新Rust變量與數(shù)據(jù)類型講解

    2022最新Rust變量與數(shù)據(jù)類型講解

    rust 是強(qiáng)類型語(yǔ)言所有變量、常量都必須有明確的數(shù)據(jù)類型,這篇文章主要介紹了Rust變量與數(shù)據(jù)類型,需要的朋友可以參考下
    2022-11-11
  • Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié)

    Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié)

    這篇文章主要為大家介紹了Rust實(shí)現(xiàn)一個(gè)表達(dá)式Parser小結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • Rust?use關(guān)鍵字妙用及模塊內(nèi)容拆分方法

    Rust?use關(guān)鍵字妙用及模塊內(nèi)容拆分方法

    這篇文章主要介紹了Rust?use關(guān)鍵字妙用|模塊內(nèi)容拆分,文中還給大家介紹use關(guān)鍵字的習(xí)慣用法,快速引用自定義模塊內(nèi)容或標(biāo)準(zhǔn)庫(kù),以此優(yōu)化代碼書(shū)寫(xiě),需要的朋友可以參考下
    2022-09-09
  • 詳解Rust 修改源

    詳解Rust 修改源

    這篇文章主要介紹了Rust 修改源的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • rust?中生成與使用protobuf的方法

    rust?中生成與使用protobuf的方法

    這篇文章主要介紹了rust中protobuf生成與使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • rust?創(chuàng)建多線程web?server的詳細(xì)過(guò)程

    rust?創(chuàng)建多線程web?server的詳細(xì)過(guò)程

    web?server?中主要的兩個(gè)協(xié)議是?http?和?tcp,tcp?是底層協(xié)議,http?是構(gòu)建在?tcp?之上的,本篇文章重點(diǎn)給大家介紹rust?創(chuàng)建多線程web?server的詳細(xì)過(guò)程,感興趣的朋友跟隨小編一起看看吧
    2023-11-11

最新評(píng)論

阿图什市| 通州区| 清涧县| 克什克腾旗| 峨边| 德保县| 新绛县| 昌乐县| 柘城县| 阳新县| 明溪县| 剑河县| 都匀市| 金乡县| 漳浦县| 南通市| 特克斯县| 留坝县| 鲁甸县| 云安县| 临城县| 会东县| 阜新市| 沾益县| 章丘市| 陇南市| 乐至县| 汽车| 平南县| 宁河县| 双牌县| 杂多县| 宣武区| 湖州市| 江西省| 晋州市| 抚宁县| 龙海市| 大新县| 陆川县| 宜城市|