Crystalのテスト周りについての覚え書き

Crystalでテストどうやって書くんだろうと調べたメモ。https://github.com/veelenga/awesome-crystal にいろいろ載っていたのでいくつか試した。
テスト機能としては、言語組み込みでrspecっぽい構文のspecが使える。よりrspecに近い機能を追加してある外部ライブラリのspec2もある。
これにPowerAssertを組み合わせる感じか。
MiniTestもあるけど試してない。

組み込みのSpec

Rubyのrspecのような仕組みが言語に組み込まれていて、「crystal spec」で実行できる。
http://crystal-lang.org/api/Spec.html を参照。
rspecと比べるとcontextやletがなかったり、before/afterもSpec.before_each、Spec.after_eachと書く必要があったりとRubyの感覚で書こうとして結構ハマった。

Crystalの場合

サンプルとしてspec.cr を作成。shouldを使う。

[ruby]
require "spec"

describe "Foo" do
Spec.before_each do
puts "Foo before_each"
end

Spec.after_each do
puts "Foo after_each"
end

describe "Bar" do
Spec.before_each do
puts "Foo::Bar before_each"
end

Spec.after_each do
puts "Foo::Bar after_each"
end

it "hoge" do
puts "hoge"
"hoge".should eq "hoge"
end

it "huga" do
puts "huga"
"huga".should eq "piyo"
end
end
end
[/ruby]

実行結果は以下の通り。

[text]
$ crystal spec spec.cr
Foo before_each
Foo::Bar before_each
hoge
.Foo after_each
Foo::Bar after_each
Foo before_each
Foo::Bar before_each
huga
FFoo after_each
Foo::Bar after_each

Failures:

1) Foo Bar huga
Failure/Error: "huga".should eq "piyo"

expected: "piyo"
got: "huga"

# ./spec.cr:28

Finished in 0.49 milliseconds
2 examples, 1 failures, 0 errors, 0 pending

Failed examples:

crystal spec ./spec.cr:26 # Foo Bar huga
[/text]

ネストの浅い箇所で定義したbefore_each/after_eachから順に実行されている。
rspecの場合はbeforeは浅い順に、afterは深い順に実行されるので最初混乱してしまった。
バグだろうか?

参考:Rubyの場合

上で書いたCrystalのspec相当のコードは以下のようになる。

[ruby]
require ‘rspec’

describe "Foo" do
before(:each) do
puts "Foo before_each"
end

after(:each) do
puts "Foo after_each"
end

describe "Bar" do
before(:each) do
puts "Foo::Bar before_each"
end

after(:each) do
puts "Foo::Bar after_each"
end

it "hoge" do
puts "hoge"
expect("hoge").to eq "hoge"
end

it "huga" do
expect("huga").to eq "piyo"
end
end
end
[/ruby]

実行結果。
beforeは浅いところから、afterは深いところから順に実行されている。

[text]
$ rspec ./spec.rb
Foo before_each
Foo::Bar before_each
hoge
Foo::Bar after_each
Foo after_each
.Foo before_each
Foo::Bar before_each
Foo::Bar after_each
Foo after_each
F

Failures:

1) Foo Bar huga
Failure/Error: expect("huga").to eq "piyo"

expected: "piyo"
got: "huga"

(compared using ==)
# ./spec.rb:27:in `block (3 levels) in <top (required)>’

Finished in 0.01156 seconds (files took 0.06919 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec.rb:26 # Foo Bar huga
[/text]

spec2

外部ライブラリ。よりrspecに近づいていて、なじみのある雰囲気。
ドキュメントは https://github.com/waterlink/spec2.cr を参照。
上で書いたspec.crをspec2で書き直すとこうなる。GlobalDSLをincludeすることでいい感じの見た目になってよい。letやsubject、expect等も使えるようになる。

[ruby]
require "spec2"
include Spec2::GlobalDSL

describe "Foo" do
before do
puts "Foo before_each"
end

after do
puts "Foo after_each"
end

context "Bar" do
before do
puts "Foo::Bar before_each"
end

after do
puts "Foo::Bar after_each"
end

it "hoge" do
puts "hoge"
expect("hoge").to eq "hoge"
end

it "huga" do
expect("huga").to eq "piyo"
end
end
end
[/ruby]

実行結果。afterの実行順序はspecと同様(rspecと逆)のようだ。

[text]
$ crystal spec spec2.cr
Foo before_each
Foo::Bar before_each
hoge
Foo after_each
Foo::Bar after_each
.Foo before_each
Foo::Bar before_each
F

In example: Foo Bar huga
Failure: Expected to be equal:
Expected: "piyo"
Actual: "huga"

[4407663170] *CallStack::unwind:Array(Pointer(Void)) +82
[4407663073] *CallStack#initialize<CallStack>:Array(Pointer(Void)) +17
[4407663032] *CallStack::new:CallStack +40
[4407776169] *Spec2::ExpectationNotMet@Exception#initialize<Spec2::ExpectationNotMet, String, Nil>:CallStack +41
[4407776092] *Spec2::ExpectationNotMet::new<String>:Spec2::ExpectationNotMet +108
[4407773796] *Spec2::Expectation(String)@Spec2::Expectation(T)#to<Spec2::Expectation(String), Spec2::Matchers::Eq>:Nil +68
[4407771919] *Spec2__Foo::Spec2__Bar::Spec2__Huga#run<Spec2__Foo::Spec2__Bar::Spec2__Huga>:Array(( -> Void)) +95
[4407769475] *Spec2::Runners::Default#run_context<Spec2::Runners::Default, Spec2::Reporters::Default, Spec2::Orders::Default, Spec2::Context>:Array(Spec2::Context) +355
[4407769950] *Spec2::Runners::Default#run_context<Spec2::Runners::Default, Spec2::Reporters::Default, Spec2::Orders::Default, Spec2::Context>:Array(Spec2::Context) +830
[4407769950] *Spec2::Runners::Default#run_context<Spec2::Runners::Default, Spec2::Reporters::Default, Spec2::Orders::Default, Spec2::Context>:Array(Spec2::Context) +830
[4407764660] *Spec2::HighRunner#run<Spec2::HighRunner>:Int32? +388
[4407765765] *Spec2@Spec2::run:Int32? +21
[4407652288] ~proc(Int32 -> Void)@./libs/spec2/spec2.cr:62 +16
[4407753648] *AtExitHandlers::run<Int32>:Array((Int32 -> Void))? +320
[4407652154] main +74

Finished in 1.16 milliseconds
Examples: 2, failures: 1
[/text]

食料と人類―飢餓を克服した大増産の文明史

人類がいかに食料生産を拡大してきたか、その歴史をたどる本。異世界にトリップ/転移/転生したときに農業チートしたい!!1と思って読んだ。
全部で十章あるが、おおまかに3つにわけられる。

  1. 人がどのように食料を効率よく得てきたのか、その背景、要因について
  2. 定住して農耕を始めた後、人が直面した問題とその解決、特に、リンと窒素について
  3. どのようにして生産効率の高い品種を作り出してきたかについて

狩猟から農耕への大転換の後、何千年もの間、土壌の養分をいかにして回復するかを探求してきており、それが解決したのが20世紀になってから、というのがすごい。しかも、その後も品種改良・遺伝子操作等、あらゆる技術を駆使して生産量向上に挑戦している。それを支えてきたのが、遺伝子にはできないことをやってのけた「文化」であり、小さな一歩の積み重ねにより様々な問題が解決されてきたわけで、今後発生するであろう様々な問題もきっといつか解決するだろうという希望を抱かせてくれた。

 

食糧と人類 ―飢餓を克服した大増産の文明史
ルース・ドフリース
日本経済新聞出版社 (2016-01-07)
売り上げランキング: 52,724

  1. 最近のライトノベルやWEB小説では異世界に転移したり転生したとき、現地にまだ存在しない農業に関する知識を使って成り上がろうとする描写がある。 

ドラム式洗濯機買った

新卒やら独身男性なら買うべきらしいドラム式洗濯機をついに使い始めて1ヶ月弱経過したので感想を書いておくことにする。

届くまでの経過

ネット通販で買った。設置までのタイムラグがあったのでメモ。

  • 1/20 22:30頃に購入。
  • 1/27 配送予定が2月中旬から下旬に伸びる
  • 2/3 再度配送予定が2月中旬から下旬に伸びるメール
  • 2/4 2/8(月)に届くとのメール
  • 2/8 午前中に届いて設置。

ドラム式にしてよかったところ

干す作業がなくなって楽になった

ボタン押して放置してたら洗濯と乾燥が終わる。すごい。寝る前か家を出る前に回すというライフサイクルに変わりつつある。干し忘れて着る服がない、ということがなくなって素晴らしい。

ドラム式で悪くなったところ、要改善なところ

キッチンマットやバスマットのような厚手の素材は脱水が失敗することがある

これは盲点だった。それ単体でいれた場合、偏りがでて止まってしまい脱水できない。縦型の場合は有無を言わさず回るんだけど。他の洗濯物と一緒に入れたらうまくいくのかもしれないけどまだ試してない。幸い、徒歩一分のところにコインラインドリーがあるのでそれを使えばどうにでもなる。もしくは、ドラム式に向いていない素材を排除していくか。

乾燥フィルタの埃掃除が面倒

毎回掃除するのがベストらしいけど忘れてしまう。しばらく放置していると乾ききらなくなることがある模様。
クイックルワイパーで毎回サッと掃除するのがよさそうではある。

まとめ

ドラム式はいいぞ。

自衛隊メンタル教官が教える 心の疲れをとる技術

2015年の後半は結構忙しくて、心身ともに疲れてるなーと感じることが多かった。メンタルについてのノウハウを得ておこうと思って読んだ本。
ムリ・ムダ・ムラの3つが軸になっており、これらとうまくつきあう方法を具体的に解説してくれている。
メンタルケアについて多く読んだわけではないのでこの本が100%正しいかどうかはわからないけど、自分の精神的な状況を見るためのベースとしてはよいと思う。

「ムリ」について

ムリをすることによる疲労は三段階に分かれており、段階が進むにつれ回復が難しくなる。早めにムリしていることに気づき、早めにケアすること。ケアの方法も、方法によっては悪影響があるらしい。動的なケアと静的なケアがあり、段階に応じて使い分ける。なんとなく疲れてるなーと思うだけじゃなくて、今は何段階目位の疲労かなと推測できるので、より客観的に自分の状況を見られるようになっているかなぁ。

 「ムダ」について

現代社会において、感情というのは過剰なものであるという。ムダな感情の例として「怒り」を出しており、メリットよりデメリットの方が大きく、不必要に怒って疲労しないことを説いている。確かに、イライラしていてよかったことって全く思いつかない。重要なのは、「怒らないようにする」ではなく「怒りを最小限に抑え、周囲に出さないようにする」ことでうまく感情とつきあうところ。確かに、抑え込むだけだといつか爆発しそうである。

「ムラ」について

「ムラ」は全体のペースを乱し、組織全体のムリにつながるという。いかに「ムラ」をなくして一定のペースを保つか。あらかじめ仕事・プライベートのスケジュールからストレスが発生しそうなタイミングを見積もり、ムリにならないように計画を立てることを推奨している。スケジュール作成や見積もりって普段の仕事でもやっているのだし、かなりやりやすそう。

 

自衛隊メンタル教官が教える 心の疲れをとる技術 (朝日新書)
下園壮太
朝日新聞出版 (2013-02-13)
売り上げランキング: 1,413