Elixirでmix newしたときには標準でExUnitのテストが実行できる状態でプロジェクトが作成されますが、
RubyとRSpscに慣れ親しんだ人にはRSpec風にテストを書きたいと思うこともあると思います。
今回はElixirのBDDフレームワーク、ESpecを使って
みます。
ESpecの導入
まずは、mix.esxのdepsにespecを追加して、mix deps.getを行います。
def deps do
[
{:ex_doc, "~> 0.19", only: :dev, runtime: false},
{:espec, "~> 1.6.3", only: [:dev, :test]}
]
end
$ docker-compose run --rm web mix deps.get
Resolving Hex dependencies...
Dependency resolution completed:
Unchanged:
earmark 1.3.1
ex_doc 0.19.2
makeup 0.8.0
makeup_elixir 0.13.0
nimble_parsec 0.5.0
New:
espec 1.6.3
meck 0.8.12
* Getting espec (Hex package)
* Getting meck (Hex package)
mix deps.getsが終了したら、mix espec.initでespecに必要なファイルを作ります。
$ docker-compose run --rm web mix espec.init
Could not find "rebar3", which is needed to build dependency :meck
I can install a local copy which is just used by Mix
Shall I install rebar3? (if running non-interactively, use "mix local.rebar --force") [Yn] Y
* creating /root/.mix/rebar
* creating /root/.mix/rebar3
===> Compiling meck
==> espec
Compiling 99 files (.ex)
warning: System.stacktrace/0 outside of rescue/catch clauses is deprecated. If you want to support only Elixir v1.7+, you must access __STACKTRACE__ inside a rescue/catch. If you want to support earlier Elixir versions, move System.stacktrace/0 inside a rescue/catch
lib/espec/example_runner.ex:254
Generated espec app
==> hello_world
* creating spec
* creating spec/spec_helper.exs
* creating spec/shared
* creating spec/shared/example_spec.exs
まだテストを記述していませんが、mix especでテストを実行して、動作することを確認します。
$ docker-compose run --rm web mix espec
Compiling 1 file (.ex)
Generated hello_world app
0 examples, 0 failures
Finished in 0.45 seconds (0.38s on load, 0.07s on specs)
Randomized with seed 288292
Specの追加と実行
Specファイルはspecディレクトリにxxx_spec.exsという形式で作成する必要があるので、
hello_world_spec.exsというファイルに以下の記述を行います。
defmodule HelloWorldSpec do
use ESpec
it do: expect HelloWorld.hello()
|> to(eq :world)
it do: expect HelloWorld.hello("dd511805")
|> to(eq "Hello, dd511805")
end
specファイルを作成したあとは再度mix specを実行して動作確認を行います。
$ docker-compose run --rm web mix espec
..
2 examples, 0 failures
Finished in 0.75 seconds (0.53s on load, 0.22s on specs)
Randomized with seed 222464
これでESpecの記述は完了です。
Specが失敗したときの挙動について
記述したSpecをわざと失敗させてExUnitのテストのときと得られる情報に差異があるか
確認してみます。
$ docker-compose run --rm web mix espec
F.
1) HelloWorldSpec
spec/hello_world_spec.exs:6: (inside example)
spec/hello_world_spec.exs:5: (example)
Expected `"Hello, dd511805"` to equal (==) `"Hello, dd"`, but it doesn't.
expected: "Hello, dd"
actual: "Hello, dd511805"
2 examples, 1 failures
Finished in 0.94 seconds (0.66s on load, 0.28s on specs)
Randomized with seed 237106
上記がespecの実行結果です。
そして下記が同じテストの失敗が発生するようにしたExUnitの結果になります。
$ docker-compose run --rm web mix test
..
1) test greets Hello, name (HelloWorldTest)
test/hello_world_test.exs:9
Assertion with == failed
code: assert HelloWorld.hello("dd511805") == "Hello, dd"
left: "Hello, dd511805"
right: "Hello, dd"
stacktrace:
test/hello_world_test.exs:10: (test)
.
Finished in 0.2 seconds
2 doctests, 2 tests, 1 failure
Randomized with seed 219476
どちらも同じような情報を得ることが出来ます。ExUnitだと stacktraceの情報も表示されているよう
ですが、今回の失敗のパターンでは、ここから有用な情報を得ることは出来ませんでした。
Spec実行時のdoctestについて
ExUnitはmix newでプロジェクトを作成した段階のテストのサンプルでdoctestの設定が書かれていますが、
ESpecを使う場合でもExUnitと同様の記述を追加することでespec実行時にdoctestを行うことが出来ます。
defmodule HelloWorldSpec do
use ESpec
doctest HelloWorld
...
end
上記の記述を追加して、mix especを実行するとdoctestも同時に実行します。
$ docker-compose run --rm web mix espec
Compiling 1 file (.ex)
....
4 examples, 0 failures
Finished in 1.05 seconds (0.83s on load, 0.21s on specs)
Randomized with seed 88580
ExUnitの場合と違って、doctestとspecの数を別に集計してくれることはないようですが、
exampleの数が増えているので、doctestもspecと同時に実行されていることがわかります。