単項マイナスと構文解析
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合
Rails7におけるシステムテストについて書きます。
コマンドラインからシステムテストのテンプレートを作成します。
$ bin/rails generate system_test words
invoke test_unit
create test/system/words_test.rb
$
/test/system/words_test.rb
がシステムテストを記述するファイルです。
ファイルを開くとWordsTestクラスの定義があります。
テストはその中に書いていきます。
require "application_system_test_case"
class WordsTest < ApplicationSystemTestCase
... ... ...
... ... ...
end
クラスの親子関係は次のようになります。
WordsTest < ApplicationSystemTestCase < ActionDispatch::SystemTestCase < ActiveSupport::TestCase
このことから、アサーションについて次のことがわかります。
ActiveSupport::TestCase
がインクルードしたアサーションはシステムテストでも使うことができる(以前の3つのテストと同様)
assert_changes
assert_difference
assert_no_changes
assert_no_difference
assert_not
assert_nothing_raised
ActionDispatch::IntegrationTest
がスーパークラスになっていたが、システムテストではスーパークラスではない。
ActionDispatch::IntegrationTest
がインクルードしていたActionDispatch::Assertions::ResponseAssertions
とActionDispatch::Assertions::RoutingAssertions
は、
システムテストではインクルードされないので、以下のアサーションは使えない。
assert_response
assert_redirect_to
assert_generates
assert_recognizes
assert_routing
ActionDispatch::SystemTestCase
がCapybara::Minitest::Assertions
をインクルードしているので、Capybaraのアサーションを使うことができる。
このアサーションはRailsのAPIリファランスには説明がない。
CapybaraのAPIリファランスにその説明がある。
よく使いそうなアサーション(個人の独断による)を以下に示す。
assert_selector(セレクタ名, オプション)
: セレクタが送られてきたHTMLページ(以下ページと略記)にあるかどうかをチェック。
オプションでよく使うのは「text: 文字列または正規表現」「count: 整数」(そのセレクタの出現回数のチェック)「visible: (true|falseなど)」(可視かどうか)など。assert_text(文字列, オプション)
: 文字列がページにあるかどうかをチェック。
オプションには「count: 整数」などが可。
デフォルトでは文字列は「可視文字列」、つまり改行やコントロールコードなどは含まないassert_button(文字列)
: 引数がボタンのidまたは表示文字列であるようなボタンがあるかどうかのチェックassert_field(文字列, オプション)
: 入力フィールドで引数の文字列にそのラベルまたは名前またはidが一致するものがあるかどうかをチェック。
オプションには「type: “textarea”」などの入力タイプの指定ができるassert_link(文字列, オプション)
: リンクで、そのidまたはテキストが引数の文字列に一致するものがあるかどうかをチェック。
オプションにはリンク先「href: 文字列または正規表現」を指定できるassert_table(文字列, オプション)
: 引数の文字列に一致するidまたはキャプションを持つ表があるかどうかをチェック。
オプションでは表の内容のチェックができるが、詳しくはAPIリファランスを参照してほしいassert_title(文字列)
: 文字列に一致するタイトルを持っているかどうかをチェック結合テストで使えたgetメソッドなどはシステムテストでは使えません。 代わりにCapybaraのメソッドを使います。 良く使われると思われるメソッドを以下に簡単に説明します。 その詳細や、他のメソッドについてはCapybaraのドキュメントを参照してください。
visit(URLまたはパス)
: URLへのGETメソッドでのアクセスをシミュレートfill_in(フィールド名, with: 文字列)
: フォーム・フィールドに文字列をセットするclick_link(テキスト)
: リンクのクリックをシミュレート。テキストはそのaタグのコンテンツ(開始タグと終了タグで挟まれた部分)click_button(テキスト)
: ボタンのクリックをシミュレート。テキストはそのボタンに表示される文字列click_on(テキスト)
: リンクまたはボタンのクリックをシミュレート。click_link
とclick_button
の両方をまとめたメソッドaccept_confirm ブロック
: ブロック(多くはリンクやボタンのクリック)を実行したときに、確認ダイアログが現れる場合、確認を受け入れる(OKをクリックなど)dismiss_confirm ブロック
: ブロック(多くはリンクやボタンのクリック)を実行したときに、確認ダイアログが現れる場合、確認を拒否する(NOやCancelをクリックなど)最後の2つは、例えば削除に対する「are you sure?」などの確認ダイアログが出る場合に必要なメソッドです。
click_on
だけではエラーになります。
ここまでで説明したメソッドは、ユーザがクリックやキーボード入力するのをシミュレートします。 テストでは、ユーザの行動をシミュレートしますので、現実の運用に近い形でのテストになります。
ここでは、ルートにアクセスしてから、検索、追加、変更、削除を一通り行うことをシミュレートしてテストします。 プログラムリストにコメントしてありますが、次の順に推移することを想定しています。
require "application_system_test_case"
class WordsTest < ApplicationSystemTestCase
test "flow from the root through every action" do
# ルートにアクセス=>indexアクションへ
visit root_url
assert_selector "h1", text: "単語帳"
# searchアクションへ
fill_in "search", with: "."
click_button "検索"
assert_selector "h1", text: "単語検索結果"
["tall","高い","house","家"].each do |s|
assert_text s
end
# newアクションへ
click_link "追加"
fill_in "word[en]", with: "stop"
fill_in "word[jp]", with: "止まる"
fill_in "word[note]", with: "The machine stopped.\n機械が止まった。\n"
wc = Word.count
# createアクションへ
click_button "作成"
# showアクションへリダイレクト
assert_text "単語を保存しました"
assert_equal 1, Word.count-wc
["stop","止まる","The machine stopped.","機械が止まった。"].each do |s|
assert_text s
end
# editアクションへ
click_link "変更"
fill_in "word[jp]", with: "止める"
fill_in "word[note]", with: "I stopped speaking.\n私は話すのをやめた。\n"
# updateアクションへ
click_button "変更"
# showアクションへリダイレクト
["stop","止める","I stopped speaking.","私は話すのをやめた。"].each do |s|
assert_text s
end
wc = Word.count
# deleteアクションへ
accept_confirm do
click_link "削除"
end
# indexアクションに戻る
assert_text "単語を削除しました"
assert_equal -1, Word.count-wc
assert_selector "h1", text: "単語帳"
end
end
プログラムを読んでもらえば、ユーザがクリックしたりキーボード入力するのをそのままシミュレートしていることが分かると思います。 いくつかポイントになる点を書きます。
assert_text
では可視文字列のみをチェックする(デフォルト動作)ので、改行をチェックすることはできません。
2行にわたる文字列は、2回に分けて1行ずつチェックします。
createアクションでデータベースの単語数が増えるのをassert_equal
でチェックしました。
assert_difference
でも可能ですが、そのブロック内にデータベースに書き込むタイミングを含まなければならないことに注意が必要です。
次のプログラムではフェイルする可能性が高いです。
assert_difference("Word.count") do
click_button "作成"
end
assert_text "単語を保存しました"
これは、ボタンクリック直後ではまだデータベースの書き込みが終わっていないため、Word.countがブロックの前後で変化していないためです。 これは次のように書くことで解決できます。
assert_difference("Word.count") do
click_button "作成"
assert_text "単語を保存しました"
end
assert_text
が画面が変わるまで待ってからチェックをしてくれるので、ブロック実行中にデータベース書き込みは行われています。
Capybaraでは、このようにアサーションが画面遷移を待つようになっているので、それに注意が必要です。
assert_difference
を使うことは可能ですが、どちらかといえばassert_equal
を使うほうが分かりやすいように思います。
削除メニューをクリックすると確認ダイアログが現れます。
Capybaraではこのようにダイアログが現れる場合はaccept_conferm
のブロックにリンクやボタンのクリックを書かなければなりません。
そうでないとエラーになります。
もし、ダイアログでCancelやNoボタンを押すことをシミュレートしたい場合はdismiss_confirm
を使います。
テストの実行にはtest:system
を引数にbin/rails
を実行します。
$ bin/rails test:system
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.11s.
yarn run v1.22.19
$ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets
app/assets/builds/application.js 394.1kb
app/assets/builds/application.js.map 721.7kb
Done in 0.20s.
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.10s.
yarn run v1.22.19
$ sass ./app/assets/stylesheets/application.bootstrap.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules
Done in 1.86s.
Running 1 tests in a single process (parallelization threshold is 50)
Run options: --seed 20243
# Running:
DEBUGGER: Attaching after process 8081 fork to child process 8111
Capybara starting Puma...
* Version 5.6.5 , codename: Birdie's Version
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:38767
.
Finished in 3.190794s, 0.3134 runs/s, 5.9546 assertions/s.
1 runs, 19 assertions, 0 failures, 0 errors, 0 skips
多くのメッセージが出ていますが、その多くはテストの準備作業です。 テスト自体は下から14行目の「Running 1 tests in a single process (parallelization threshold is 50)」以下になります。 下から4行目のドットがテストの成功を示しています。 さらに、その詳細は、最終行のテスト1、アサーション19、フェイルとエラーは0だったことが分かります。
システムテストではブラウザ画面が表示されます。 これは画面を見ることができて良いともいえますが、逆に煩わしいともいえます。 画面表示の部分を無くしたヘッドレスブラウザを使うことでこの問題を解決できます。
設定についてはRails Guideを参照してください。
この記事の例から分かると思いますが、システムテストでは実際の運用に近い形でのテストができます。 本当にシミュレーションという感じです。 演劇でいえば舞台稽古、コンサートでいえばリハーサルのようなものです。
したがって、Railsのウェブアプリケーションは最終的にはシステムテストを書かなければならないと思います。 そうであれば、結合テストは省略される可能性もあるでしょう。 これはそれぞれのプロジェクトでの考え方になると思います。
今回でRailsの記事が7本になりました。 ここでRailsは終わりになります。 次回以降は別のトピックを取り上げたいと思います。
単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合
パーサ・ジェネレータとは 少し複雑な文法 四則(加減乗除)計算のBNF Racc で実装 クラス定義、BNFの記述部分 ヘッダー、インナー、フッター コンパイルと実行 演算子の優先順位と結合における左右の優先順位 まとめ
StrScanライブラリのドキュメント 字句解析とは StrScanライブラリ StrScanライブラリを使った字句解析 実例
lbtというgemを作って公開してみた lbtはどんなgemか ファイルの配置 lbt.gemspec Rakefile gemのビルド RubyGems.orgへのアップロード 補足・・rake/gempackagetaskサブライブラリについて
文字列のエンコーディングに頭を悩ませることはほとんどなくなりました。 なぜなら、どのアプリ、システムもUTF-8を使うようになったからです。 Rubyでもエンコーディングの問題が起こることはまず無いでしょう。 ですが、今回はエンコーディングの考え方を整理してみたいと思います。
Fiberを書いたときから、次はスレッドを書こうと思っていましたが、時間がかかってしまいました。 その理由は、期待したとおりのスレッドの効果がなかったためです。 今回はそのことを書きますが、これはRubyのスレッドの抱えている問題なのか、自分のやり方が悪いのかははっきりしていません。
Fiberは「ノンプリエンプティブな軽量スレッド」とRubyのマニュアルに記載されています。
今回はRubyプログラムから自動的にドキュメントを作成するRDocについて書きたいと思います。 私はこのことについて、エキスパートではありません。 この記事も、初心者の体験談だと考えてください。
Ruby/Gtkの記事を先日書いたときに、「これはかなり使える」という手応えを感じたので、WordBook(Railsで作った単語帳プログラム)のGTK 4版を作りました。 プログラムは「徒然なるままにRuby」のGitHubレポジトリに置いてあります。 レポジトリをダウンロードし、ディレクトリ_example/...
今回はGTK 3とGTK 4をRubyで使うライブラリについて書きたいと思います。
今回もRubyとGUIのトピックです。 Glimmerを取り上げます。
Rubyはグラフィックについて弱い印象があります。 しかし、グラフィックはデバイスに関することなので、言語そのものには直接の関係はないはずで、あるとすればライブラリです。 今後グラフィック関係のgemが開発されることに期待しましょう。
Rails7におけるシステムテストについて書きます。
前回作ったWordbook(リソースフル)のテストを書いてみます。 RailsのテストはminitestをRails用に拡張したものです。
今回はRailsの慣例に沿った形でWordbookを作り直します。
今回はWordBookの検索と削除についてです。
今回はRailsにおけるデータの作成と保存、そして変更について説明します。 そのベースになるモデルとデータベースの話から始め、appendとchangeの動作について詳しく説明します。
一般に、HTMLは文書の構造を表し、CSSはその体裁(見栄え)を表します。 Railsは最終的にCSSを含むHTML文書を出力するので、この2つについての理解が必須です。 この記事ではとくにCSSの人気ライブラリであるBootstrapを紹介します。 BootstrapはJavascriptも含んでいます。
Rubyの最も人気のあるアプリケーションであるRuby on Railsを取り上げようと思い、書き始めました。 予想してはいましたが、相当な分量になってしまいました。 そのため、何回かに分けて記事にすることにします。 また、対象となる読者のレベルをどうしようかと考えましたが、「徒然Ruby」が基礎的な内容から始ま...
Rubyのライブラリ管理システムのRubygemsとコマンドgemおよびbundlerについて説明します。
minitestについて連続して2回書いてきました。 「minitestはドキュメントが少ない」という人がいますが、私も同感です。 例えば、モックとスタブの説明も少ないです。 そこで、今回はmock.rbのソースコードを参考に、モックの私的ドキュメントを書いてみました。 あくまで私個人の考えであり、minites...
今回もminitestの話です。 mockとstubに焦点をあて説明します。
アプリ作成の記事でminitestを使いました。 今回はminitestについて、また一般にテストについて、私の考えを書こうと思います。
今回はメソッドの呼び出し制限ついて説明します。 呼び出し制限にはpublic、private、protectedの3つがあります。
今回は特異メソッド、特異クラス定義、名前空間、モジュール関数について説明します。
2023/10/29 追記:この記事は新しく書き直しました。 古い記事で使っていたGitHubのCalcが大幅にアップデートされたためです。 そこで、この記事に合うようなプログラムsimple_calcを新たに作りました。 このプログラムは本レポジトリの_example/simple_calcにあります。
if〜elsif〜・・・〜else〜endは皆さん良く使うでしょうか? これは場合分けで良く使われる方法です。 これと同様の制御構造にcase文があります。 Cのswitch文に似ていますが、より強力な機能を持っています。 if-else-endよりも高い能力があるといえます。
Procオブジェクトを生成するメソッドlambdaについて説明します。
今回はブロックを一般化したオブジェクトProcを説明します。
ブロック付きメソッドの作り方を説明します。
モジュールには名前空間とミックスイン(Mix-in)の2つの機能があります。 ここではミックスインについて説明します。
クラスの親子関係
Rubyの演算子とその再定義について書きます。
今回からクラスとインスタンスを定義、生成する方法を説明します
Kernelモジュールのメソッドはどこでも使うことができます。 そのメソッドの中には便利で有用なものが多いです。
ここでは私が便利だと思ったメソッドを紹介します。
実数
今回はシンボルとハッシュについて説明します。
文字列は最も使うオブジェクトのひとつです。 特にウェブ・アプリケーションでは、コンテンツだけでなくHTMLのタグやCSSを含めすべてが文字列です。 Rubyは文字列オブジェクトのメソッドが充実しており、またパターンマッチのための正規表現も充実しています。
配列は、どのプログラミング言語にもあると思います。 複数の要素を一括して扱うことができるのが配列です。 Rubyの配列はメソッドが充実しているので、プログラムを効率的、機能的に書くのに役立ちます。
今回の目標はインスタンスです。 インスタンスを説明するために、ローカル変数と文字列オブジェクトを事前に扱います。
今回はメソッド定義です。 メソッド定義はRubyの核心ですが、今回はトップレベルに限って説明します。 この限定によって、内容はかなり易しくなっています。
ブロックはRubyの特長です。 ブロックのおかげで記述が非常にすっきりと分かりやすくなります。 今回はブロックをイテレータの本体として使う方法を説明します。
ここではRubyの最も基本的なオブジェクトである整数について説明します。
「徒然なるままに」をネットで調べてみると、「することもなく、手持無沙汰なのにまかせてという意味」とありました。 まさに、自分の現状を言い当てた言葉。 しかも、ブログに書くネタもなかなか思いつかない日々。