はじめに
Privateメソッドのテスト要否に対する部分は一旦置いとく。
テストしたいぜー、でも、同じファイルに書くのは、テストコードが多くなりすぎて見通し悪くなるから避けたいぜー
みたいな感じで色々試行錯誤してたどり着いた(と言ってもモジュールの可視性とかの話を調べれば一発だったっぽい)
ので備忘録的にメモしているやつでござーます。
とりあえず動かしてみたいという方へ
シンプルにテストを書いてみよう
適当なプロジェクトを作ります。
cargo new testcode_example --lib
トップレベルのフォルダ構成
./
│ .gitignore
│ Cargo.lock
│ Cargo.toml
│
├───src
│ lib.rs
│
└───target
(snip)
それでは、src/lib.rs
に以下を追記していきます
pub fn pow(x: u32) -> u32 {
pow_impl(x)
}
fn pow_impl(x: u32) -> u32 {
x * x
}
#[test]
fn pow_test() {
let x = pow(2);
assert_eq!(x, 4)
}
#[test]
fn pow_impl_test() {
let x = pow_impl(2);
assert_eq!(x, 4)
}
よいですね。ただ、テストが増えていくと見通しが悪くなってしまいます。
というわけで、テストは分けましょう。
あと、src/lib.rs
に書き続けるのも自分の趣味ではないので計算をするので、別モジュール(math)へ集約しようと思います。
テストを分ける前の準備(ファイル分割)
./
│ .gitignore
│ Cargo.lock
│ Cargo.toml
│
├───src
│ │ lib.rs
│ │
│ └───math <-- 新しく作ったディレクトリ
│ exponentiation.rs <-- ここに実装を移しました。
│ mod.rs
└───target
(snip)
pub fn pow(x: u32) -> u32 {
pow_impl(x)
}
fn pow_impl(x: u32) -> u32 {
x * x
}
#[test]
fn pow_test() {
let x = pow(2);
assert_eq!(x, 4)
}
#[test]
fn pow_impl_test() {
let x = pow_impl(2);
assert_eq!(x, 4)
}
pub mod exponentiation; // モジュールを公開する
代わりにlibにはmathモジュールを使うコードを書いておきます。
pub mod math;
fn calc() {
// 公開されてるAPIなのでOK
let pow = math::exponentiation::pow(10);
// 公開されていないAPIなのでビルドエラーが起こる
let pow_inner = math::exponentiation::pow_impl(10);
assert_eq!(pow, 100);
}
移植が完了しました。
次は、テストコードも分離していきます。
テストコードの分離(失敗編)
./
│ .gitignore
│ Cargo.lock
│ Cargo.toml
│
├───src
│ │ lib.rs
│ │
│ └───math
│ exponentiation.rs
│ exponentiation_tests.rs <-- テストメソッド群
│ mod.rs
└───target
(snip)
pub fn pow(x: u32) -> u32 {
pow_impl(x)
}
fn pow_impl(x: u32) -> u32 {
x * x
}
use crate::math::exponentiation::*;
#[test]
fn pow_test() {
let x = pow(2);
assert_eq!(x, 4)
}
#[test]
fn pow_impl_test() {
let x = pow_impl(2);
assert_eq!(x, 4)
}
pub mod exponentiation;
#[cfg(test)]
pub mod exponentiation_tests; // テストモジュールを公開してcargo testできるようにする
ですよねー!!!!!!
pow_implはexponentiation_tests.rs
から見えないよ!って言われてます。
同じファイルには書きたくないし、pubを付けて公開もしたくない・・・どうしよう???
モジュール内での可視性はpubにし、モジュールの可視性をprivateにする(成功)
Rustはファイル単位での可視性を設定できるわけですが
モジュールでの可視性も設定できるというのが自分の中では盲点でした。
pub mod exponentiation;
mod exponentiation_impl; // 追加:pubは付けずにモジュールを定義する
#[cfg(test)]
pub mod exponentiation_tests;
pub fn pow_impl(x: u32) -> u32 {
x * x
}
use crate::math::exponentiation_impl::*; // 追加
pub fn pow(x: u32) -> u32 {
pow_impl(x)
}
use crate::math::exponentiation::*;
use crate::math::exponentiation_impl::*; // 追加
#[test]
fn pow_test() {
let x = pow(2);
assert_eq!(x, 4)
}
#[test]
fn pow_impl_test() {
let x = pow_impl(2);
assert_eq!(x, 4)
}
./
│ .gitignore
│ Cargo.lock
│ Cargo.toml
│
├───src
│ │ lib.rs
│ │
│ └───math
│ exponentiation.rs
│ exponentiation_impl.rs <-- テストしたいけど非公開にしたいメソッド
│ exponentiation_tests.rs <-- テストメソッド群
│ mod.rs
└───target
(snip)
めでたく通りましたし、lib.rsで隠蔽されてるimplメソッドを呼ぼうとするとちゃんとエラーになりました。
若干手間ですが、ファイル分離ができてとても幸せな感じですね。
それでは。