??個(gè)人專欄:
?? 算法設(shè)計(jì)與分析:算法設(shè)計(jì)與分析_IT閆的博客-CSDN博客
??Java基礎(chǔ):Java基礎(chǔ)_IT閆的博客-CSDN博客
??c語言:c語言_IT閆的博客-CSDN博客
??MySQL:數(shù)據(jù)結(jié)構(gòu)_IT閆的博客-CSDN博客
??數(shù)據(jù)結(jié)構(gòu):??????數(shù)據(jù)結(jié)構(gòu)_IT閆的博客-CSDN博客
??C++:C++_IT閆的博客-CSDN博客
??C51單片機(jī):C51單片機(jī)(STC89C516)_IT閆的博客-CSDN博客
??基于HTML5的網(wǎng)頁設(shè)計(jì)及應(yīng)用:基于HTML5的網(wǎng)頁設(shè)計(jì)及應(yīng)用_IT閆的博客-CSDN博客??????
??python:python_IT閆的博客-CSDN博客
??離散數(shù)學(xué):離散數(shù)學(xué)_IT閆的博客-CSDN博客
????????Linux:????Linux_Y小夜的博客-CSDN博客
??Rust:Rust_Y小夜的博客-CSDN博客
歡迎收看,希望對(duì)大家有用!
目錄
??編寫和運(yùn)行測(cè)試
??測(cè)試(函數(shù))
??解剖測(cè)試函數(shù)
?? 斷言(Assert)
??使用assert!宏檢查測(cè)試結(jié)果
??使用assert_eq!和assert_ne!測(cè)試相等性
??自定義錯(cuò)誤信息
??使用should_panic檢查恐慌
??讓should_panic更加精準(zhǔn)
??在測(cè)試中使用Result,e>
??編寫和運(yùn)行測(cè)試
??測(cè)試(函數(shù))
Rust 中的測(cè)試函數(shù)是用來驗(yàn)證非測(cè)試代碼是否是按照期望的方式運(yùn)行的。測(cè)試函數(shù)體通常執(zhí)行如下三種操作:
- 設(shè)置任何所需的數(shù)據(jù)或狀態(tài)
- 運(yùn)行需要測(cè)試的代碼
- 斷言其結(jié)果是我們所期望的
??解剖測(cè)試函數(shù)
? ? ? ? 測(cè)試成功:
????????Rust 中的測(cè)試就是一個(gè)帶有?
test
?屬性注解的函數(shù)。屬性(attribute)是關(guān)于 Rust 代碼片段的元數(shù)據(jù);第五章中結(jié)構(gòu)體中用到的?derive
?屬性就是一個(gè)例子。為了將一個(gè)函數(shù)變成測(cè)試函數(shù),需要在?fn
?行之前加上?#[test]
。當(dāng)使用?cargo test
?命令運(yùn)行測(cè)試時(shí),Rust 會(huì)構(gòu)建一個(gè)測(cè)試執(zhí)行程序用來調(diào)用被標(biāo)注的函數(shù),并報(bào)告每一個(gè)測(cè)試是通過還是失敗。????????每次使用 Cargo 新建一個(gè)庫項(xiàng)目時(shí),它會(huì)自動(dòng)為我們生成一個(gè)測(cè)試模塊和一個(gè)測(cè)試函數(shù)。這個(gè)模塊提供了一個(gè)編寫測(cè)試的模板,為此每次開始新項(xiàng)目時(shí)不必去查找測(cè)試函數(shù)的具體結(jié)構(gòu)和語法了。因?yàn)檫@樣當(dāng)然你也可以額外增加任意多的測(cè)試函數(shù)以及測(cè)試模塊。
????????實(shí)際編寫測(cè)試代碼之前,讓我們先通過嘗試那些自動(dòng)生成的測(cè)試模版來探索測(cè)試是如何工作的。接著,我們會(huì)寫一些真正的測(cè)試,調(diào)用我們編寫的代碼并斷言它們的行為的正確性。
$ cargo new adder --lib Created library `adder` project $ cd adder
#[cfg(test)] mod tests { #[test] fn it_works() { let result = 2 + 2; assert_eq!(result, 4); } }
????????現(xiàn)在讓我們暫時(shí)忽略?
tests
?模塊和?#[cfg(test)]
?注解并只關(guān)注函數(shù)本身。注意?fn
?行之前的?#[test]
:這個(gè)屬性表明這是一個(gè)測(cè)試函數(shù),這樣測(cè)試執(zhí)行者就知道將其作為測(cè)試處理。tests
?模塊中也可以有非測(cè)試的函數(shù)來幫助我們建立通用場(chǎng)景或進(jìn)行常見操作,必須每次都標(biāo)明哪些函數(shù)是測(cè)試。????????測(cè)試失?。?/strong>
????????當(dāng)測(cè)試函數(shù)中出現(xiàn) panic 時(shí)測(cè)試就失敗了。每一個(gè)測(cè)試都在一個(gè)新線程中運(yùn)行,當(dāng)主線程發(fā)現(xiàn)測(cè)試線程異常了,就將對(duì)應(yīng)測(cè)試標(biāo)記為失敗。
#[cfg(test)] mod tests { #[test] fn exploration() { assert_eq!(2 + 2, 4); } #[test] fn another() { panic!("Make this test fail"); } }
?? 斷言(Assert)
??使用assert!宏檢查測(cè)試結(jié)果
??assert!
?宏由標(biāo)準(zhǔn)庫提供,在希望確保測(cè)試中一些條件為?true
?時(shí)非常有用。需要向?assert!
?宏提供一個(gè)求值為布爾值的參數(shù)。如果值是?true
,assert!
?什么也不做,同時(shí)測(cè)試會(huì)通過。如果值為?false
,assert!
?調(diào)用?panic!
?宏,這會(huì)導(dǎo)致測(cè)試失敗。assert!
?宏幫助我們檢查代碼是否以期望的方式運(yùn)行。#[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn can_hold(&self, other: &Rectangle) -> bool { self.width > other.width && self.height > other.height } }
??使用assert_eq!和assert_ne!測(cè)試相等性
????????測(cè)試功能的一個(gè)常用方法是將需要測(cè)試代碼的值與期望值做比較,并檢查是否相等。可以通過向?
assert!
?宏傳遞一個(gè)使用?==
?運(yùn)算符的表達(dá)式來做到。不過這個(gè)操作實(shí)在是太常見了,以至于標(biāo)準(zhǔn)庫提供了一對(duì)宏來更方便的處理這些操作 ——?assert_eq!
?和?assert_ne!
。這兩個(gè)宏分別比較兩個(gè)值是相等還是不相等。當(dāng)斷言失敗時(shí)它們也會(huì)打印出這兩個(gè)值具體是什么,以便于觀察測(cè)試?為什么?失敗,而?assert!
?只會(huì)打印出它從?==
?表達(dá)式中得到了?false
?值,而不是打印導(dǎo)致?false
?的兩個(gè)值。pub fn add_two(a: i32) -> i32 { a + 2 } #[cfg(test)] mod tests { use super::*; #[test] fn it_adds_two() { assert_eq!(4, add_two(2)); } }
? ? ? ? 我們傳遞給?
assert_eq!
?宏的第一個(gè)參數(shù)?4
?,它等于調(diào)用?add_two(2)
?的結(jié)果。測(cè)試中的這一行?test tests::it_adds_two ... ok
?中?ok
?表明測(cè)試通過!????????在代碼中引入一個(gè) bug 來看看使用?
assert_eq!
?的測(cè)試失敗是什么樣的。修改?add_two
?函數(shù)的實(shí)現(xiàn)使其加?3
:pub fn add_two(a: i32) -> i32 { a + 3 }
$ cargo test Compiling adder v0.1.0 (file:///projects/adder) Finished test [unoptimized + debuginfo] target(s) in 0.61s Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4) running 1 test test tests::it_adds_two ... FAILED failures: ---- tests::it_adds_two stdout ---- thread 'main' panicked at 'assertion failed: `(left == right)` left: `4`, right: `5`', src/lib.rs:11:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: tests::it_adds_two test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass `--lib`
????????測(cè)試捕獲到了 bug!
it_adds_two
?測(cè)試失敗,錯(cuò)誤信息告訴我們斷言失敗了,它告訴我們?assertion failed: `(left == right)`
?以及?left
?和?right
?的值是什么。這個(gè)錯(cuò)誤信息有助于我們開始調(diào)試:它說?assert_eq!
?的?left
?參數(shù)是?4
,而?right
?參數(shù),也就是?add_two(2)
?的結(jié)果,是?5
??梢韵胂螽?dāng)有很多測(cè)試在運(yùn)行時(shí)這些信息是多么的有用。????????需要注意的是,在一些語言和測(cè)試框架中,斷言兩個(gè)值相等的函數(shù)的參數(shù)被稱為?
expected
?和?actual
,而且指定參數(shù)的順序非常重要。然而在 Rust 中,它們則叫做?left
?和?right
,同時(shí)指定期望的值和被測(cè)試代碼產(chǎn)生的值的順序并不重要。這個(gè)測(cè)試中的斷言也可以寫成?assert_eq!(add_two(2), 4)
,這時(shí)失敗信息仍同樣是?assertion failed: `(left == right)`
。
???assert_ne!
?宏在傳遞給它的兩個(gè)值不相等時(shí)通過,而在相等時(shí)失敗。在代碼按預(yù)期運(yùn)行,我們不確定值?會(huì)?是什么,不過能確定值絕對(duì)?不會(huì)?是什么的時(shí)候,這個(gè)宏最有用處。
???assert_eq!
?和?assert_ne!
?宏在底層分別使用了?==
?和?!=
。當(dāng)斷言失敗時(shí),這些宏會(huì)使用調(diào)試格式打印出其參數(shù),這意味著被比較的值必須實(shí)現(xiàn)了?PartialEq
?和?Debug
?trait。所有的基本類型和大部分標(biāo)準(zhǔn)庫類型都實(shí)現(xiàn)了這些 trait。對(duì)于自定義的結(jié)構(gòu)體和枚舉,需要實(shí)現(xiàn)?PartialEq
?才能斷言它們的值是否相等。需要實(shí)現(xiàn)?Debug
?才能在斷言失敗時(shí)打印它們的值。因?yàn)檫@兩個(gè) trait 都是派生 trait。
??自定義錯(cuò)誤信息
????????也可以向?
assert!
、assert_eq!
?和?assert_ne!
?宏傳遞一個(gè)可選的失敗信息參數(shù),可以在測(cè)試失敗時(shí)將自定義失敗信息一同打印出來。任何在?assert!
?的一個(gè)必需參數(shù)和?assert_eq!
?和?assert_ne!
?的兩個(gè)必需參數(shù)之后指定的參數(shù)都會(huì)傳遞給?format!
?宏,所以可以傳遞一個(gè)包含?{}
?占位符的格式字符串和需要放入占位符的值。自定義信息有助于記錄斷言的意義;當(dāng)測(cè)試失敗時(shí)就能更好的理解代碼出了什么問題。pub fn greeting(name: &str) -> String { format!("Hello {}!", name) } #[cfg(test)] mod tests { use super::*; #[test] fn greeting_contains_name() { let result = greeting("Carol"); assert!(result.contains("Carol")); } }
????????這個(gè)程序的需求還沒有被確定,因此問候文本開頭的?
Hello
?文本很可能會(huì)改變。然而我們并不想在需求改變時(shí)不得不更新測(cè)試,所以相比檢查?greeting
?函數(shù)返回的確切值,我們將僅僅斷言輸出的文本中包含輸入?yún)?shù)。????????讓我們通過將?
greeting
?改為不包含?name
?在代碼中引入一個(gè) bug 來測(cè)試失敗時(shí)是怎樣的:pub fn greeting(name: &str) -> String { String::from("Hello!") }
????????如果僅僅告訴了我們斷言失敗了和失敗的行號(hào)。一個(gè)更有用的失敗信息應(yīng)該打印出?
greeting
?函數(shù)的值。讓我們?yōu)闇y(cè)試函數(shù)增加一個(gè)自定義失敗信息參數(shù):帶占位符的格式字符串,以及?greeting
?函數(shù)的值:#[test] fn greeting_contains_name() { let result = greeting("Carol"); assert!( result.contains("Carol"), "Greeting did not contain name, value was `{}`", result ); }
??使用should_panic檢查恐慌
????????除了檢查返回值之外,檢查代碼是否按照期望處理錯(cuò)誤也是很重要的。
????????可以通過對(duì)函數(shù)增加另一個(gè)屬性?
should_panic
?來實(shí)現(xiàn)這些。這個(gè)屬性在函數(shù)中的代碼 panic 時(shí)會(huì)通過,而在其中的代碼沒有 panic 時(shí)失敗。pub struct Guess { value: i32, } impl Guess { pub fn new(value: i32) -> Guess { if value < 1 || value > 100 { panic!("Guess value must be between 1 and 100, got {}.", value); } Guess { value } } } #[cfg(test)] mod tests { use super::*; #[test] #[should_panic] fn greater_than_100() { Guess::new(200); } }
??讓should_panic更加精準(zhǔn)
????????然而?
should_panic
?測(cè)試結(jié)果可能會(huì)非常含糊不清。should_panic
?甚至在一些不是我們期望的原因而導(dǎo)致 panic 時(shí)也會(huì)通過。為了使?should_panic
?測(cè)試結(jié)果更精確,我們可以給?should_panic
?屬性增加一個(gè)可選的?expected
?參數(shù)。測(cè)試工具會(huì)確保錯(cuò)誤信息中包含其提供的文本。// --snip-- impl Guess { pub fn new(value: i32) -> 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 ); } Guess { value } } } #[cfg(test)] mod tests { use super::*; #[test] #[should_panic(expected = "less than or equal to 100")] fn greater_than_100() { Guess::new(200); } }
????????這個(gè)測(cè)試會(huì)通過,因?yàn)?
should_panic
?屬性中?expected
?參數(shù)提供的值是?Guess::new
?函數(shù) panic 信息的子串。我們可以指定期望的整個(gè) panic 信息,在這個(gè)例子中是?Guess value must be less than or equal to 100, got 200.
?。?expected
?信息的選擇取決于 panic 信息有多獨(dú)特或動(dòng)態(tài),和你希望測(cè)試有多準(zhǔn)確。在這個(gè)例子中,錯(cuò)誤信息的子字符串足以確保函數(shù)在?else if value > 100
?的情況下運(yùn)行。
??在測(cè)試中使用Result<T,E>
????????目前為止,我們編寫的測(cè)試在失敗時(shí)都會(huì) panic。我們也可以使用?
Result<T, E>
?編寫測(cè)試!這是一個(gè)延伸自示例 11-1 的測(cè)試,使用?Result<T, E>
?重寫,并在失敗時(shí)返回?Err
?而非 panic:#[cfg(test)] mod tests { #[test] fn it_works() -> Result<(), String> { if 2 + 2 == 4 { Ok(()) } else { Err(String::from("two plus two does not equal four")) } } }
????????現(xiàn)在?
it_works
?函數(shù)的返回值類型為?Result<(), String>
。在函數(shù)體中,不同于調(diào)用?assert_eq!
?宏,而是在測(cè)試通過時(shí)返回?Ok(())
,在測(cè)試失敗時(shí)返回帶有?String
?的?Err
。文章來源:http://www.zghlxwxcb.cn/news/detail-845413.html????????不能對(duì)這些使用?
Result<T, E>
?的測(cè)試使用?#[should_panic]
?注解。為了斷言一個(gè)操作返回?Err
?成員,不要使用對(duì)?Result<T, E>
?值使用問號(hào)表達(dá)式(?
)。而是使用?assert!(value.is_err())
。文章來源地址http://www.zghlxwxcb.cn/news/detail-845413.html
到了這里,關(guān)于【Rust】——編寫自動(dòng)化測(cè)試(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!