/var/log/messages

Apr 29, 2019 - 2 minute read - Comments - programming

Property-Based Testing with PropEr, Erlang, Elixir (2)

Property-Based Testing with PropEr, Erlang, Elixir の Chapter 2 です。

Writing Properties

どうも PropEr の term() というナニがイメージできず。Google してみたら以下なコンテンツを発見。

あ、でもこれ、erlang なナニですね。

を確認してみます。

むむむ

よく分からない。とりあえず諸々スルーで進めてみます。

Structure of Properties

以下なナニをでっちあげています。

defmodule PbtTest do
  use ExUnit.Case
  use PropCheck

  # Properties
  property "description of what the property does" do
    forall type <- my_type() do
      boolean(type)
    end
  end

  # Helpers
  defp boolean(_) do
    true
  end

  # Generators
  def my_type() do
    term()
  end
end

properties の部分が雛形、みたいな理解で良いのかどうか。

Default Generators

以下に列挙しておきます。

  • any()
    • term() と同義とのこと
  • atom()
    • Erlang atoms
  • binary()
    • Binary data aligned on bytes
  • boolean()
    • true あるいは false な atom
  • chooose(Min, Max)
    • Min と Max の間の integer
  • float()
    • floating point number
  • integer()
  • list()
  • non_empty(Gen)
  • number()
  • range(Min, Max)
    • choose と同義
  • string()
    • list(char()) と同義
  • {Ta, T2, …}
    • {boolean(), char()} -> {true, 1}

ようやっと term() の意味が (を

Putting It All Together

以下が例示されています。

property "finds biggest element" do
  forall x <- list(integer()) do
    biggest(x) == List.last(Enum.sort(x))
  end
end

左辺な手続きが未定義ですね。このままでは試験は動きません。とりあえず以下が例示されています。

def biggest([head|_tail]) do
  head
end

単純に先頭要素、ってだけなので駄目ですが動作確認してみます。

最大な要素、を洗濯する Elixir 的な手続き

パタンマッチを使って云々、てのが格好良いですね。

def biggest([head|tail]) do
  biggest(tail, head)
end

def biggest([], max) do
  max
end

def biggest([head|tail], max) when head >= max do
  biggest(tail, head)
end

def biggest([head|tail], max) when head < max do
  biggest(tail, max)
end

ありゃ

試験にパスしないな。同じエラーみたいに見えます。

  1) property finds biggest element (PbtTest)
     test/pbt_test.exs:12
     Property Elixir.PbtTest.property finds biggest element() failed. Counter-Example is:
     [[]]
     
     Consider running `MIX_ENV=test mix propcheck.clean` if a bug in a generator was
     identified and fixed. PropCheck cannot identify changes to generators. See
     https://github.com/alfert/propcheck/issues/30 for more details.

ええと、MIX_ENV=test mix propcheck.clean しても同じ動作です。

non_empty/1 使え、って書いてあるぞ。でも挙動は変わらずで。

mix propcheck して mix test したら通ったぞorz

最新版のソースコードは以下です。。

defmodule PbtTest do
  use ExUnit.Case
  use PropCheck

  # Properties
  property "description of what the property does" do
    forall type <- my_type() do
      boolean(type)
    end
  end

  property "finds biggest element" do
    forall x <- non_empty(list(integer())) do
      biggest(x) == List.last(Enum.sort(x))
    end
  end

  # Helpers
  defp boolean(_) do
    true
  end

  def biggest([head|tail]) do
    biggest(tail, head)
  end

  def biggest([], max) do
    max
  end

  def biggest([head|tail], max) when head >= max do
    biggest(tail, head)
  end

  def biggest([head|tail], max) when head < max do
    biggest(tail, max)
  end

  # Generators
  def my_type() do
    term()
  end
end

commit 作成してビーチパーリーに向かいますorz