5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ElixirAdvent Calendar 2014

Day 9

ドキュメントトリガーテスト駆動 Elixir ( Document Trigger Test Driven Elixir ) #elixir #tdd

Posted at

ドキュメントトリガーテスト駆動 Elixir ( Document Trigger Test Driven Elixir )

概要

Elixir でドキュメントの Example を元にテスト駆動開発をします

前提

Elixri の Doctests を利用します。
詳しくは下記記事を参照
Elixir | Doctests

仕様

FizzBuzzプログラムを作成します

  • インターフェースは Fizzbuzz.fizzbuzz(from, to)
  • from, to ともに Integer のみ許容
    • Integer 以外を指定した場合は、RuntimeError を投げる
  • from から to までの FizzBuzz の結果を配列として返却
  • 15 の倍数は "FizzBuzz"
  • 3 の倍数は "Fizz"
  • 5 の倍数は "Buzz"
  • 3/5/15 の倍数以外は 入力数値をそのまま返却

手順

プロジェクトの作成

mix コマンドでプロジェクトテンプレートを生成します。
今回は

  • lib/fizzbuzz.ex
  • test/fizzbuzz_test.ex

のみを編集します。

$ mix new fizzbuzz
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/fizzbuzz.ex
* creating test
* creating test/test_helper.exs
* creating test/fizzbuzz_test.exs

テストを実行

自動生成直後は、空のプロダクトコードと成功するテスト Example が実装されているため、
1件テストをパスします。

$ mix test
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app
.

Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 tests, 0 failures

テストコード:Example をテストするために doctest を呼び出します。

これ以降テストコードは一切変更しません

  • test/fizzbuzz_test.exs
defmodule FizzbuzzTest do
  use ExUnit.Case
  doctest Fizzbuzz
end
  • テストを実行。結果は 0 件
$ mix test --trace
FizzbuzzTest


Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
0 tests, 0 failures

プロダクトコード:数値をそのまま返却する Example を追加

  • Example を追加
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]
  """
  def fizzbuzz(from, to) do
  end
end
  • テストを実行
    未実装のためテストに失敗します
$ mix test --trace
lib/fizzbuzz.ex:11: warning: variable from is unused
lib/fizzbuzz.ex:11: warning: variable to is unused
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (1) (0.00ms)

  1) test doc at Fizzbuzz.fizzbuzz/2 (1) (FizzbuzzTest)
     test/fizzbuzz_test.exs:3
     Doctest failed
     code: Fizzbuzz.fizzbuzz(1,2) === [1, 2]
     lhs:  nil
     stacktrace:
       lib/fizzbuzz.ex:11: Fizzbuzz (module)



Finished in 0.07 seconds (0.07s on load, 0.00s on tests)
1 tests, 1 failures

Randomized with seed 926333

プロダクトコード:数値をそのまま返却する Example を実装

  • lib/fizzbuzz.ex
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(&1))
  end
end
  • テストを実行
    テストをパスしました
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (1) (5.7ms)


Finished in 0.07 seconds (0.07s on load, 0.00s on tests)
1 tests, 0 failures

プロダクトコード:Fizz の Example を追加

  • lib/fizzbuzz.exs
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(&1))
  end
end
  • テストを実行
    未実装のためテストに失敗します
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (1) (4.9ms)
  * doc at Fizzbuzz.fizzbuzz/2 (2) (0.02ms)

  1) test doc at Fizzbuzz.fizzbuzz/2 (2) (FizzbuzzTest)
     test/fizzbuzz_test.exs:3
     Doctest failed
     code: Fizzbuzz.fizzbuzz(3, 3) === ["Fizz"]
     lhs:  [3]
     stacktrace:
       lib/fizzbuzz.ex:18: Fizzbuzz (module)



Finished in 0.07 seconds (0.07s on load, 0.00s on tests)
2 tests, 1 failures

Randomized with seed 118398

プロダクトコード:Fizz を実装

  • lib/fizzbuzz.ex
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  defp fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end
  defp fizzbuzz(n) do
    n
  end
end
  • テストを実行
    テストをパスしました
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (2) (4.4ms)
  * doc at Fizzbuzz.fizzbuzz/2 (1) (0.06ms)


Finished in 0.09 seconds (0.09s on load, 0.00s on tests)
2 tests, 0 failures

Randomized with seed 629312

プロダクトコード:Buzz の Example を追加

  • lib/fizzbuzz.exs
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]

      # only Buzz
      iex> Fizzbuzz.fizzbuzz(5, 5)
      ["Buzz"]
      iex> Fizzbuzz.fizzbuzz(10, 10)
      ["Buzz"]
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  defp fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end

  defp fizzbuzz(n) do
    n
  end
end
  • テストを実行
    未実装のためテストに失敗します
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (2) (4.0ms)
  * doc at Fizzbuzz.fizzbuzz/2 (1) (0.02ms)
  * doc at Fizzbuzz.fizzbuzz/2 (3) (0.06ms)

  1) test doc at Fizzbuzz.fizzbuzz/2 (3) (FizzbuzzTest)
     test/fizzbuzz_test.exs:3
     Doctest failed
     code: Fizzbuzz.fizzbuzz(5, 5) === ["Buzz"]
     lhs:  [5]
     stacktrace:
       lib/fizzbuzz.ex:23: Fizzbuzz (module)



Finished in 0.08 seconds (0.08s on load, 0.00s on tests)
3 tests, 1 failures

Randomized with seed 857202

プロダクトコード:Buzz を実装

  • lib/fizzbuzz.ex
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]

      # only Buzz
      iex> Fizzbuzz.fizzbuzz(5, 5)
      ["Buzz"]
      iex> Fizzbuzz.fizzbuzz(10, 10)
      ["Buzz"]
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  defp fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end

  defp fizzbuzz(n) when rem(n, 5) == 0 do
    "Buzz"
  end

  defp fizzbuzz(n) do
    n
  end
end
  • テストを実行
    テストをパスしました
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (3) (3.9ms)
  * doc at Fizzbuzz.fizzbuzz/2 (1) (0.02ms)
  * doc at Fizzbuzz.fizzbuzz/2 (2) (0.1ms)


Finished in 0.08 seconds (0.08s on load, 0.00s on tests)
3 tests, 0 failures

Randomized with seed 677241

プロダクトコード:FizzBuzz の Example を追加

  • lib/fizzbuzz.exs
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]

      # only Buzz
      iex> Fizzbuzz.fizzbuzz(5, 5)
      ["Buzz"]
      iex> Fizzbuzz.fizzbuzz(10, 10)
      ["Buzz"]

      # only FizzBuzz
      iex> Fizzbuzz.fizzbuzz(15, 15)
      ["FizzBuzz"]
      iex> Fizzbuzz.fizzbuzz(30, 30)
      ["FizzBuzz"]

      # mix case
      iex> Fizzbuzz.fizzbuzz(1, 15)
      [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  defp fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end

  defp fizzbuzz(n) when rem(n, 5) == 0 do
    "Buzz"
  end

  defp fizzbuzz(n) do
    n
  end
end
  • テストを実行
    未実装のためテストに失敗します
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (2) (4.9ms)
  * doc at Fizzbuzz.fizzbuzz/2 (1) (0.03ms)
  * doc at Fizzbuzz.fizzbuzz/2 (3) (0.05ms)
  * doc at Fizzbuzz.fizzbuzz/2 (5) (0.1ms)

  1) test doc at Fizzbuzz.fizzbuzz/2 (5) (FizzbuzzTest)
     test/fizzbuzz_test.exs:3
     Doctest failed
     code: Fizzbuzz.fizzbuzz(1, 15) === [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]
     lhs:  [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz",
            13, 14, "Fizz"]
     stacktrace:
       lib/fizzbuzz.ex:33: Fizzbuzz (module)

  * doc at Fizzbuzz.fizzbuzz/2 (4) (0.1ms)

  2) test doc at Fizzbuzz.fizzbuzz/2 (4) (FizzbuzzTest)
     test/fizzbuzz_test.exs:3
     Doctest failed
     code: Fizzbuzz.fizzbuzz(15, 15) === ["FizzBuzz"]
     lhs:  ["Fizz"]
     stacktrace:
       lib/fizzbuzz.ex:33: Fizzbuzz (module)



Finished in 0.09 seconds (0.09s on load, 0.00s on tests)
5 tests, 2 failures

Randomized with seed 64741

プロダクトコード:FizzBuzz を実装

  • lib/fizzbuzz.ex
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]

      # only Buzz
      iex> Fizzbuzz.fizzbuzz(5, 5)
      ["Buzz"]
      iex> Fizzbuzz.fizzbuzz(10, 10)
      ["Buzz"]

      # only FizzBuzz
      iex> Fizzbuzz.fizzbuzz(15, 15)
      ["FizzBuzz"]
      iex> Fizzbuzz.fizzbuzz(30, 30)
      ["FizzBuzz"]

      # mix case
      iex> Fizzbuzz.fizzbuzz(1, 15)
      [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  defp fizzbuzz(n) when rem(n, 15) == 0 do
    "FizzBuzz"
  end

  defp fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end

  defp fizzbuzz(n) when rem(n, 5) == 0 do
    "Buzz"
  end

  defp fizzbuzz(n) do
    n
  end
end
  • テストを実行
    テストをパスしました
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (2) (13.8ms)
  * doc at Fizzbuzz.fizzbuzz/2 (1) (0.01ms)
  * doc at Fizzbuzz.fizzbuzz/2 (4) (0.07ms)
  * doc at Fizzbuzz.fizzbuzz/2 (3) (0.02ms)
  * doc at Fizzbuzz.fizzbuzz/2 (5) (0.01ms)


Finished in 0.1 seconds (0.09s on load, 0.01s on tests)
5 tests, 0 failures

Randomized with seed 768461

プロダクトコード:from / to に不正な引数( Integer 以外)を指定する Example を追加

  • lib/fizzbuzz.exs
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]

      # only Buzz
      iex> Fizzbuzz.fizzbuzz(5, 5)
      ["Buzz"]
      iex> Fizzbuzz.fizzbuzz(10, 10)
      ["Buzz"]

      # only FizzBuzz
      iex> Fizzbuzz.fizzbuzz(15, 15)
      ["FizzBuzz"]
      iex> Fizzbuzz.fizzbuzz(30, 30)
      ["FizzBuzz"]

      # mix case
      iex> Fizzbuzz.fizzbuzz(1, 15)
      [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]

      # args 'to' not integer
      iex> Fizzbuzz.fizzbuzz("1", 15)
      ** (RuntimeError) invalid argument
          (fizzbuzz) lib/fizzbuzz.ex:37: Fizzbuzz.fizzbuzz/2

      # args 'to' not integer
      iex> Fizzbuzz.fizzbuzz(1, "15")
      ** (RuntimeError) invalid argument
  """
  def fizzbuzz(from, to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  defp fizzbuzz(n) when rem(n, 15) == 0 do
    "FizzBuzz"
  end

  defp fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end

  defp fizzbuzz(n) when rem(n, 5) == 0 do
    "Buzz"
  end

  defp fizzbuzz(n) do
    n
  end
end
  • テストを実行
    未実装のためテストに失敗します
$ mix test --trace
warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell)
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (6) (10.5ms)

  1) test doc at Fizzbuzz.fizzbuzz/2 (6) (FizzbuzzTest)
     test/fizzbuzz_test.exs:3
     Doctest failed: expected exception RuntimeError with message "invalid argument" but got Protocol.UndefinedError with message "protocol Range.Iterator not implemented for \"1\""
     code: Fizzbuzz.fizzbuzz("1", 15)
     stacktrace:
       lib/fizzbuzz.ex:42: Fizzbuzz (module)

  * doc at Fizzbuzz.fizzbuzz/2 (1) (1.4ms)
  * doc at Fizzbuzz.fizzbuzz/2 (4) (1.8ms)
  * doc at Fizzbuzz.fizzbuzz/2 (5) (1.2ms)
  * doc at Fizzbuzz.fizzbuzz/2 (2) (0.07ms)
  * doc at Fizzbuzz.fizzbuzz/2 (7) (6.9ms)

  2) test doc at Fizzbuzz.fizzbuzz/2 (7) (FizzbuzzTest)
     test/fizzbuzz_test.exs:3
     Doctest failed: expected exception RuntimeError with message "invalid argument" but got FunctionClauseError with message "no function clause matching in Range.Iterator.Integer.next/2"
     code: Fizzbuzz.fizzbuzz(1, "15")
     stacktrace:
       lib/fizzbuzz.ex:42: Fizzbuzz (module)

  * doc at Fizzbuzz.fizzbuzz/2 (3) (0.2ms)


Finished in 0.1 seconds (0.1s on load, 0.02s on tests)
7 tests, 2 failures

Randomized with seed 32922

プロダクトコード:from / to に不正な引数( Integer 以外)を指定した場合に、RuntimeError を投げるように実装

  • lib/fizzbuzz.ex
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]

      # only Buzz
      iex> Fizzbuzz.fizzbuzz(5, 5)
      ["Buzz"]
      iex> Fizzbuzz.fizzbuzz(10, 10)
      ["Buzz"]

      # only FizzBuzz
      iex> Fizzbuzz.fizzbuzz(15, 15)
      ["FizzBuzz"]
      iex> Fizzbuzz.fizzbuzz(30, 30)
      ["FizzBuzz"]

      # mix case
      iex> Fizzbuzz.fizzbuzz(1, 15)
      [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]

      # args 'to' not integer
      iex> Fizzbuzz.fizzbuzz("1", 15)
      ** (RuntimeError) invalid argument
          (fizzbuzz) lib/fizzbuzz.ex:37: Fizzbuzz.fizzbuzz/2

      # args 'to' not integer
      iex> Fizzbuzz.fizzbuzz(1, "15")
      ** (RuntimeError) invalid argument
  """
  def fizzbuzz(from, to) when is_integer(from) and is_integer(to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  def fizzbuzz(_from, _to) do
    raise "invalid argument"
  end

  defp fizzbuzz(n) when rem(n, 15) == 0 do
    "FizzBuzz"
  end

  defp fizzbuzz(n) when rem(n, 3) == 0 do
    "Fizz"
  end

  defp fizzbuzz(n) when rem(n, 5) == 0 do
    "Buzz"
  end

  defp fizzbuzz(n) do
    n
  end
end
  • テストを実行
    テストをパスしました
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (6) (0.9ms)
  * doc at Fizzbuzz.fizzbuzz/2 (1) (3.8ms)
  * doc at Fizzbuzz.fizzbuzz/2 (4) (0.03ms)
  * doc at Fizzbuzz.fizzbuzz/2 (7) (0.04ms)
  * doc at Fizzbuzz.fizzbuzz/2 (2) (0.03ms)
  * doc at Fizzbuzz.fizzbuzz/2 (3) (0.05ms)
  * doc at Fizzbuzz.fizzbuzz/2 (5) (0.02ms)


Finished in 0.1 seconds (0.1s on load, 0.00s on tests)
7 tests, 0 failures

Randomized with seed 951920

プロダクトコード:リファクタリング

各プライベート関数の処理が短いので1行で記述するように修正します

  • lib/fizzbuzz.ex
defmodule Fizzbuzz do
  @doc ~S"""
  FizzBuzz.

  ## Examples

      # only other numbers
      iex> Fizzbuzz.fizzbuzz(1,2)
      [1, 2]

      # only Fizz
      iex> Fizzbuzz.fizzbuzz(3, 3)
      ["Fizz"]
      iex> Fizzbuzz.fizzbuzz(6, 6)
      ["Fizz"]

      # only Buzz
      iex> Fizzbuzz.fizzbuzz(5, 5)
      ["Buzz"]
      iex> Fizzbuzz.fizzbuzz(10, 10)
      ["Buzz"]

      # only FizzBuzz
      iex> Fizzbuzz.fizzbuzz(15, 15)
      ["FizzBuzz"]
      iex> Fizzbuzz.fizzbuzz(30, 30)
      ["FizzBuzz"]

      # mix case
      iex> Fizzbuzz.fizzbuzz(1, 15)
      [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]

      # args 'to' not integer
      iex> Fizzbuzz.fizzbuzz("1", 15)
      ** (RuntimeError) invalid argument
          (fizzbuzz) lib/fizzbuzz.ex:37: Fizzbuzz.fizzbuzz/2

      # args 'to' not integer
      iex> Fizzbuzz.fizzbuzz(1, "15")
      ** (RuntimeError) invalid argument
  """
  def fizzbuzz(from, to) when is_integer(from) and is_integer(to) do
    from..to |> Enum.map(&(fizzbuzz/1))
  end

  def fizzbuzz(_from, _to), do: raise "invalid argument"
  defp fizzbuzz(num) when rem(num, 15) == 0, do: "FizzBuzz"
  defp fizzbuzz(num) when rem(num, 5) == 0, do: "Buzz"
  defp fizzbuzz(num) when rem(num, 3) == 0, do: "Fizz"
  defp fizzbuzz(num), do: num
end
  • テストを実行
    テストをパスしました。
    テストを壊さずにリファクタリングに成功しました。
$ mix test --trace
Compiled lib/fizzbuzz.ex
Generated fizzbuzz.app

FizzbuzzTest
  * doc at Fizzbuzz.fizzbuzz/2 (4) (4.8ms)
  * doc at Fizzbuzz.fizzbuzz/2 (7) (1.9ms)
  * doc at Fizzbuzz.fizzbuzz/2 (1) (0.1ms)
  * doc at Fizzbuzz.fizzbuzz/2 (2) (0.1ms)
  * doc at Fizzbuzz.fizzbuzz/2 (5) (0.1ms)
  * doc at Fizzbuzz.fizzbuzz/2 (3) (0.1ms)
  * doc at Fizzbuzz.fizzbuzz/2 (6) (0.08ms)


Finished in 0.1 seconds (0.1s on load, 0.01s on tests)
7 tests, 0 failures

Randomized with seed 216728

完成したプロジェクトを実行

$ mix run -e 'IO.inspect Fizzbuzz.fizzbuzz(1, 30)'
[1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14,
 "FizzBuzz", 16, 17, "Fizz", 19, "Buzz", "Fizz", 22, 23, "Fizz", "Buzz", 26,
 "Fizz", 28, 29, "FizzBuzz"]

$ mix run -e 'IO.inspect Fizzbuzz.fizzbuzz("1", 30)'
** (RuntimeError) invalid argument
    (fizzbuzz) lib/fizzbuzz.ex:46: Fizzbuzz.fizzbuzz/2
    (stdlib) erl_eval.erl:657: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:865: :erl_eval.expr_list/6
    (stdlib) erl_eval.erl:407: :erl_eval.expr/5
    (elixir) lib/code.ex:140: Code.eval_string/3
    (elixir) lib/enum.ex:537: Enum."-each/2-lists^foreach/1-0-"/2

$ mix run -e 'IO.inspect Fizzbuzz.fizzbuzz(1, "30")'
** (RuntimeError) invalid argument
    (fizzbuzz) lib/fizzbuzz.ex:46: Fizzbuzz.fizzbuzz/2
    (stdlib) erl_eval.erl:657: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:865: :erl_eval.expr_list/6
    (stdlib) erl_eval.erl:407: :erl_eval.expr/5
    (elixir) lib/code.ex:140: Code.eval_string/3
    (elixir) lib/enum.ex:537: Enum."-each/2-lists^foreach/1-0-"/2

$ mix run -e 'IO.inspect Fizzbuzz.fizzbuzz(15, 1)'
["FizzBuzz", 14, 13, "Fizz", 11, "Buzz", "Fizz", 8, 7, "Fizz", "Buzz", 4, "Fizz", 2, 1]

Complete!

明日は @keithseahus さんです。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?