>100 Views
April 05, 26
スライド概要
SAS言語を中心として,解析業務担当者・プログラマなのコミュニティを活性化したいです
testthatの紹介 Takashi Uota EPS Corporation 2026-04-08
Agenda 1. 2. 3. 4. testthatとは何か testthatの利用でできること testthatの関数紹介 testthatの利用方法 2
testthatとは何か testthatはRのテストフレームワーク テストフレームワーク: プログラムが正しく動くかを効率よく確認するための仕組み 例:mean関数の挙動を確認する パッケージの開発において、よく利用される ⇒他のパッケージに比べて高い確率でSuggestsに含まれている 補足 Suggests:利用の上でインストールは必須ではないが、あると便利 テスト、vignette、拡張機能などで使用される。 3
testthatはなぜ作られたのか testthat登場までのR利用の背景 • もともとは統計解析を行うための言語で、個人・研究用途が中心 ⇒ソフトウェア品質管理の文化があまりない。 • 2000年代にパッケージが増えはじめ、利用上の問題が生じてきた。 ⇒パッケージ更新で動かなくなる、依存関係で壊れる。 ⇒テストツールとしてRunit、svUnitがあったが使いづらくて普及しなかった。 • 2010年前後にさまざまな変化がありテストフレームワークの重要性や普及につながる文化が根付き 始める。 • • • • • ソフトウェアの大規模化に伴い、自動テストの必要性が高まる 他言語で開発中に“テストを書くことが習慣化し、そのための方法論・ツールが確立 Git/GitHubの普及 オープンソース開発の拡大 2011年にtestthat登場! 4
testthat普及の理由 • devtoolsとの統合 一つのコマンドでテスト実行できることになりテストを習慣化 • tidyverseとの相乗効果 読みやすく、一貫した文法、人間が理解しやすいというtydyverseの思想と同様 • 学習コストの低さ 書き方がシンプルでとてもわかりやすい • CRAN文化との相性 CRANの品質要求を満たすために最適である 5
実際にtestthatはどんなことに使えるのか? Rパッケージ開発で 品質管理に使う 関数の結果が正しい か確認する エラーや警告の挙動 を確認する コード変更・修正後に 壊れていないか確認 する 6
testthatの関数 Version 3.3.2 document参照 CheckReporter comparison-expectations DebugReporter equality-expectations expect_all_equal expect_error expect_invisible expect_length expect_match expect_named expect_no_error expect_null expect_output expect_setequal expect_silent expect_snapshot expect_snapshot_file expect_snapshot_value expect_success expect_vector extract_test fail FailReporter inheritance-expectations is_testing JunitReporter ListReporter LlmReporter local_edition local_mocked_bindings local_mocked_r6_class local_mocked_s3_method local_test_context LocationReporter logical-expectations MinimalReporter mock_output_sequence MultiReporter ProgressReporter RStudioReporter set_state_inspector SilentReporter skip SlowReporter snapshot_accept snapshot_download_gh StopReporter SummaryReporter TapReporter TeamcityReporter teardown_env test_dir test_file test_package test_path test_that try_again use_catch 7
testthatの関数 – カテゴライズ testthatパッケージの関数は概ね以下のようにカテゴライズが可能 • テストを書く・実行する機能 • • • • • テストの枠組みを作る関数 期待値をチェックする関数(Expectation) エラー・警告を確認する関数 テスト実行・管理の関数 テスト補助関数(セットアップなど) • テスト結果を表示する機能 • テストの結果を見せ方を決める関数 8
testthatの関数 – testの枠組みを作る⚫ test_that Passedの例 Usage Failureの例 test_that(desc, code) どのようなテストを 実施するのか 明確にしておくことで 管理しやすくなる。 Arguments desc Test name. Names should be brief, but evocative. It’s common to write the description so that it reads like a natural sentence, e.g. test_that("multiplication works", { ... }). code Test code containing expectations. Braces ({}) should always be used in order to get accurate location data for test failures Reference Manualより抜粋 9
testthatの関数 – 期待値をチェックする関数(Expectation) 代表例 関数 用途 equality-expectations 値の一致 expect_all_equal すべての要素が同じ値か expect_length レコード数の確認 expect_named 名前(列名・names)が正しいか expect_null 結果が存在しないことの確認 expect_vector ベクトルの型と構造 expect_setequal 順序を無視して同じ集合か expect_match 文字列がパターンに一致するか expect_idential 値以外に型・属性・順序まで完全一致するか expect_snapshot_file 過去に保存した結果と一致するか ※エラー・警告系のExpectation関数は別の分類として次のページに記載しています。 10
testthatの関数 – エラー・警告を確認する関数 代表例 関数 用途 expect_error Errorが出ることを確認 expect_no_error Errorが出ないことを確認 expect_warning Warningが出ることを確認 expect_no_warning Warningが出ないことを確認 expect_message メッセージが出ることを確認 expect_no_message メッセージが出ないことを確認 expect_success ErrorもWarningも出ないことを確認 11
testthatの関数 – テスト実行・管理の関数 フォルダ構成 tests ├ source │├ 01_xxxx.R │├ 02_xxxx.R │├ : └ testthat ├ test_01_xxxx.R ├ test_02_xxxx.R ├: ●test_file 1つのテストファイルだけ実行する test_file("tests/testthat/test_01_xxxx.R") ● test_dir ディレクトリ内のテストをまとめて実行する test_dir("tests/testthat") パッケージ構成 Packagename1 ├ DESCRIPTION ├ NAMESPACE ├R │ └ Program.R └ tests └ testthat └ test_Program01.R 基本ルール • テストファイルは”test-”また は”test_”で始めること • テストファイルは tests/testthat/ に置くこと パッケージ構成 ● test_package Rパッケージ内のテ ストを実行する test_package("packa gename1") CRANからのインストールの場合、testsのフォルダ以下は含まれない。 GitHubからのインストールの場合、準備されていれば保持されている。 作業ディレクトリ ├ Packagename1 │ ├ DESCRIPTION │ ├ NAMESPACE │├R │ │ └ Program.R │ └ tests └ testthat │ └ Packagename2 ● devtools::test 作業ディレクトリ内の開 発中のパッケージのテ ストを実行する devtools::test() 12
testthatの関数 – テスト補助関数(セットアップなど) カテゴリ 関数 用途 Skip系 skip, skip_if, skip_if_not_installed, skip_on_cran 未実装部分や条件に応じてスキップ Local系 local_options, local_envvar, local_tempdir 一時的にオプション、環境を変更して、テスト後に環境を 元に戻す。 参考 オプションにはどんなものがあるのか(例) 環境変数にはどんなものがあるのか(例) digits 小数点以下の表示桁数 API_KEY APIキー scipen 科学表記抑制 PATH 実行パス width 表示幅 HOME ホームディレクトリ max.print 表示する最大要素数 TMPDIR 一時ディレクトリ warn Warninの扱い LANG 言語設定 stringAsFactor s 文字列をfactor変数にする か否か LC_ALL ロケール LC_TIME 日付フォーマット na.action 欠損値の扱い DB接続関連 repos CRANミラー DB_HOST/ DB_USER encoding 文字コード https_proxy HTTPSプロキシ Q. Local系の関数で変更したオプションや環 境はいつ戻るのか? A. そのテスト、または、そのコードブロックが 終わった時点で戻る test_that("example", { local_options(digits = 3) }) ← 変更状態を保持 ← 関数の実行終了で戻る 13
testthatの関数 – テストの結果を見せ方を決める関数 代表例 Junit形式はWarningの概念がないので注意 expect_no_warningを用いる等で対策は可能 ● ProgressReporter ● JunitReporter testthat::ProgressReporter$new() testthat::JunitReporter$new(file = “ファイル名”) ● SummaryReporter Rのスクリプトで見やすくすることも可能 testthat::SummaryReporter$new ●MultiReporter testthat::MultiReporter$new(list( 複数指定が可能 testthat::ProgressReporter$new(), testthat::JunitReporter$new(file = “ファイル名”) )) 14
testthatの利用方法 – 関数の動作確認 年齢をカテゴリ分けする例
tests
├ source
│├ Function_derive_agegr1.R
└ testthat
├ test_derive_agegr1.R
② テスト用のスクリプトを書く
test_derive_agegr1.R
source("function/function_derive_agegr1.R")
test_that("derive_agegr1 works correctly for vector input", {
age <- c(NA, 20, 39, 40, 50, 64, 65, 80)
result <- derive_agegr1(age)
expected <- c(
NA_character_, "<40","<40","40<= <65", "40<= <65",
"40<= <65", ">=65",">=65"
)
expect_equal(result, expected)
})
① 関数を用意する
function_derive_agegr1.R
derive_agegr1 <- function(age) {
case_when(
is.na(age) ~ NA_character_,
age < 40 ~ "<40",
age >= 40 & age < 65 ~ "40<= <65",
age >= 65 ~ ">=65"
)
}
③ 実行する ※ホームディレクトリは”tests”の前提
library("testthat")
library ("dplyr")
test_file("testthat/test_derive_agegr1.R")
[実行結果]
[ FAIL 0 | WARN 0 | SKIP 0 | PASS 1 ]>
15
testthatの利用方法 - DS/TFLs作成 データセットや帳票作成においては使い道があるのか? 【想定できるtestthatの利用シーン】 ① 社内で標準関数を準備する際にテストしておきたい。 ② 目視で確認している部分を自動化したい。 ③ regression testに使いたい。 ⇒ダブルプログラミングと異なる視点でのQCとして利用できる。 ①はともかく、②③は+αで プログラムを書くことになりコ ストは増える方向にしかなら ないのではないか? 本当にそうでしょうか?リスクベースに応じた アプローチが求められるようになりつつある。 それぞれの利点を活かして、より少ないリソー スでより効果的なQCを目指していくことが求め られると考える。 ⇒ぜひ皆さんと意見交換したいです。 16
まとめ • testthatはRのテストフレームワーク • パッケージ開発においては欠かせない存在 • testthatは期待値の確認だけではなく、周辺機能も豊富 • 繰返しtestthatによるチェックを行う際にはフォルダ構成等を整えておく 必要がある。 • 使い方次第で、これからのデータセット作成や統計解析においてQCの ベースを担う素質が十分にある。 17
参考文献 [1] Wickham, H. (2011). testthat: Getting started with testing. https://vita.had.co.nz/papers/testthat.pdf [2] Wickham, H. testthat: Unit testing for R. https://testthat.r-lib.org/ (最終閲覧日: 2026年3月31日) 18