Rust入坑指南 步步為營

2022-07-04 15:09:10 字數 4453 閱讀 7375

俗話說:「測試寫得好,獎金少不了。」

有經驗的開發人員通常會通過單元測試來保證**基本邏輯的正確性。如果你是一名新手開發者,並且還沒體會到單元測試的好處,那麼建議你先讀一下我之前的一篇文章**潔癖系列(七):單元測試的地位。

寫單元測試一般需要三個步驟:

準備測試用例,測試用例要能覆蓋盡可能多的**

執行需要測試的**

判斷結果,是否是你希望得到的結果

了解了這些以後,我們就來看看在rust中應該怎麼寫單元測試。

首先我們建立乙個library專案

$ cargo new adder --lib

created library `adder` project

然後在src/lib.rs檔案中開始寫測試**

#[cfg(test)]

mod tests

}

此時在命令列執行cargo test就會得到測試結果

可以看到,結果顯示,rust執行了一項測試並且測試通過。後面的doc-tests我們先放下,以後再聊。

當然,這並不是我們常見的測試,在日常開發中,我們通常是先寫我們的業務**然後再對各個函式進行單元測試,最後還會對某個模組進行整合測試。那麼我們就來模擬一下日常開發過程中應該如何來寫測試。

我們仍然是用上面的專案,先來在src/lib.rs中寫一段「業務**」

pub fn add_two(a: i32) -> i32 

fn internal_adder(a: i32, b: i32) -> i32

這是一段非常簡單的**,對外暴露的函式只是乙個加2的功能,內部呼叫了乙個兩數相加的函式。現在我們就對這個內部函式做乙個單元測試。

#[cfg(test)]

mod tests

}

在測試模組中,如果想要使用我們業務**中的函式,就需要通過use super::*;將其引入可用範圍。接著,還是執行cargo test,測試結果與剛才類似。

測了半天全是通過的沒什麼意思,單元測試真正的作用是要發現**中的問題,所以我們來嘗試乙個錯誤的試一下。假設我們希望2+2等於5。

rust就會將錯誤棧列印出來,根據結果提示,這並不是完整的錯誤棧,我們還可以將rust_backtrace設定為full來檢視更加詳細的資訊。這裡我就不做演示了。

接下來我們再演示一下整合測試。我們通常將整合測試單獨放到乙個目錄中,在lib.rs檔案中,rust識別測試mod的名稱是tests,同樣的,我們在src下建立tests目錄。tests目錄下就是我們的所有整合測試**。

如圖,integration_test是我們測試**的檔案,common目錄下的mod.rs檔案中是一些整合測試必要的配置。這裡我們只是放了乙個空的setup函式。

在整合測試中,我們就要像正常他人使用我們的**時那樣來進行測試,首先需要將我們的mod引入到可用範圍,當然還需要加上common的mod。

use adder;

mod common;

#[tests]

fn it_adds_two()

接著就可以測試我們對外暴露的函式了。

ok,整合測試的方法我們也掌握了。現在來看看一直被我們忽略的doc-tests吧。

我們已經知道,rust中的注釋是雙斜線//,像我們剛剛寫的library**,如果想要把它發布到crate.io上讓別人使用,那麼我們就需要增加相應的文件,這裡文件的每行都應該是三斜線///開頭,而文件中也應該放一些例子供他人參考。

/// adds two to the number given.

////// # examples

////// ```

/// let arg = 5;

/// let answer = adder::add_two(arg);

////// assert_eq!(7, answer);

/// ```

pub fn add_two(a: i32) -> i32

現在我給add_two函式加上了文件,我們再次執行cargo test命令。

現在我們就明白了,doc-tests測試就是執行我們文件中的例子。

到目前為止,我們已經知道了在rust中如何寫測試**了。接下來我們再來了解幾個比較常用的特性。

執行指定的測試**

我們在開發過程中肯定不會每次都去跑全量的單元測試,那樣太浪費時間了。通常是我們開發完乙個功能之後,編寫對應的單元測試,然後單獨跑這個測試。那麼rust中能不能單獨跑乙個單元測試呢?答案是肯定的。

相信細心的同學已經發現了,rust測試結果中,是針對每個測試單獨統計結果,並且每個測試都有自己的名字,像我們前面寫的it_worksinternal。假設我們的**中同時存在這兩個函式,如果你想要單獨跑internal這乙個測試,就可以使用cargo test internal命令。

你也可以使用這種方法來執行多個名稱類似的測試,假如我們有名稱為internal_a的測試,那麼執行cargo test internal命令時它也會被執行。

忽略某個測試

當我們有乙個測試執行時間非常長的時候,我們一般不會輕易去執行,這時如果你想要執行多個測試,除了用我們上面提到的方法,去指定不同的名稱列表以外。還可以把這個測試忽略掉。

現在我不想執行internal測試了,只需要對**進行如下改動:

#[test]

#[ignore]

fn internal()

這時再來執行測試,結果如圖所示。

我們發現此時internal測試已經被忽略了。

測試異常情況

除了測試**邏輯正常的情況,我們有時還需要測試一些異常情況,比如接收到非法引數時程式能否返回我們希望看到的異常。

我們首先來看一下如何測試程式返回異常資訊。

rust為我們提供了乙個叫做should_panic的註解。我們可以使用它來測試程式是否返回異常:

pub fn add_two(a: i32) -> i32 

fn internal_adder(a: i32, b: i32) -> i32

a + b

}#[cfg(test)]

mod tests

}

此時我們執行測試時就會發現internal測試通過,因為它發生了執行緒恐慌,這是我們希望看到的結果。

另外,我們還可以再指定我們具體期望的異常,那麼就可以在should_panic後面加上expected引數。

#[test]

#[should_panic(expected = "a should be positive")]

fn internal()

大家可以自行執行一下這段測試**看看效果。

文中我向大家介紹了在rust中如何進行單元測試、整合測試,還有比較特殊的文件測試。最後還介紹了3種常見的測試特性。

最後想友情提醒大家一下,在開發過程中,不要寫完一堆功能後再開始寫單元測試,這時你很有可能會因為測試**過於繁瑣而放棄。建議大家每寫乙個功能,隨即開始進行單元測試,這樣也能立即看到自己的**的執行效果,提高成就感。這就是所謂的「步步為營」。

步步為營 79 快取

快取cache,一種空間換取時間的技術,適用於經常訪問,不常修改的資料.1 寫入快取 1.1 方法一 cache message ab 1.2 方法二 cache.insert message ab 1.3 其他過載 insert string key,object value,cachedepen...

步步為營 50 事務

說明 比較常用 1 事務的四大特性 1.1 原子性atomicity 乙個事務中包含的多個sql語句,要麼同時成功,要麼同時失敗.1.2 一致性consistency 事務必須使資料庫從從乙個一致性狀態變成另外乙個一致性狀態.銀行轉賬 1.3 隔離性 isolation 各個事務執行互不干擾 鎖 1...

io nio socket步步為營(三)NIO

原理 運用reactor模式 selector是核心 分發器a multiplexor of selectablechannel objects。能檢測任意個註冊過的channel上的事件,並分發事件,內部實現不用考慮,封裝的好處。client沒必要用nio,使用中的client server,需要...