如何在Elixir测试中使用常量?

时间:2017-04-22 08:04:02

标签: elixir

我在主模块中以这种方式定义一个常量:

@end_digits_adjusters [11, 12, 14, 21, 22, 23] 

以下是我试图测试的方法:

defmodule PriceOptimizerTest do
  use ExUnit.Case
  doctest PriceOptimizer

  test "get_random_adjuster() randomizer" do
    adj_num = PriceOptimizer.get_random_adjuster()
    is_in? = adj_num in @end_digits_adjusters
    assert is_in? == true

  end
end

这不起作用。但是当我在测试中明确指定常量值时,它确实有效。像这样......

is_in? = adj_num in [11, 12, 14, 21, 22, 23]

我错过了一个让Elixir能够识别测试中模块常数的步骤吗?

2 个答案:

答案 0 :(得分:4)

在其他语言中流行的共享常量在Elixir中不是一种流行的模式。我个人发现,大多数时候我不需要使用这种模式。但是有一些应用程序我已经在它们上构建了很多继电器。

当我需要它们时,我有一个常量模块,我使用以下模块:

defmodule Constants do
  @moduledoc """
  An alternative to use @constant_name value approach to defined reusable
  constants in elixir.

  This module offers an approach to define these in a
  module that can be shared with other modules. They are implemented with
  macros so they can be used in guards and matches

  ## Examples:

  Create a module to define your shared constants

      defmodule MyConstants do
        use Constants

        define something,   10
        define another,     20
      end

  Use the constants

      defmodule MyModule do
        require MyConstants
        alias MyConstants, as: Const

        def myfunc(item) when item == Const.something, do: Const.something + 5
        def myfunc(item) when item == Const.another, do: Const.another
      end

  """

 defmacro __using__(_opts) do
    quote do
      import Constants
    end
  end

  @doc "Define a constant"
  defmacro constant(name, value) do
    quote do
      defmacro unquote(name), do: unquote(value)
    end
  end

  @doc "Define a constant. An alias for constant"
  defmacro define(name, value) do
    quote do
      constant unquote(name), unquote(value)
    end
  end

  @doc """
    Import an hrl file.

    Create constants for each -define(NAME, value).
  """
  defmacro import_hrl(file_name) do
    list = parse_file file_name
    quote bind_quoted: [list: list] do
      for {name, value} <- list do
        defmacro unquote(name)(), do: unquote(value)
      end
    end
  end

  defp parse_file(file_name) do
    for line <- File.stream!(file_name, [], :line) do
      parse_line line
    end
    |> Enum.filter(&(not is_nil(&1)))
  end

  defp parse_line(line) do
    case Regex.run ~r/-define\((.+),(.+)\)\./, line do
      nil -> nil
      [_, name, value] ->
        {String.strip(name) |> String.downcase |> String.to_atom, String.strip(value) |> parse_value}
      _ -> nil
    end
  end

  defp parse_value(string) do
    case Integer.parse string do
      :error -> filter_string(string)
      {num, _} -> num
    end
  end

  defp filter_string(string), do: String.replace(string, "\"", "")
end

情侣笔记:

  • 他们从事模式匹配工作!
  • 不要导入常量模块。很难找到定义的地方
  • 为了简洁而别名模块`别名MyConstantsMod,as:Const
  • 此模块还支持使用Erlang hrl文件
  • 注意require陈述。 define是一个宏。
  • 使用sublime的多光标和vi键绑定时,转换C #define语句列表只是几个关键点:)

答案 1 :(得分:1)

我担心,Elixir's module attributes仅在定义的模块中可用。这是因为在编译阶段这些属性在代码中处于联机状态。

如果你想让它们公开可访问,你需要用函数包装它,例如:

defmodule MyMod do
  @test "hello"

  def test, do: @test
end

所以:

MyMod.test # => "hello"

希望有所帮助!