【问题标题】:Testing config / system env getters测试配置/系统环境获取器
【发布时间】:2021-03-12 08:18:21
【问题描述】:

我有一个名为Auth.app_id 的函数,它首先尝试从应用程序的配置中读取app_id,如果丢失,将查找系统环境。

测试此类功能的最佳实践是什么?当然,事先在测试中使用Application.put_envSystem.put_env 是非常糟糕的做法,因为我们使用全局变量进行操作,并且不可能进行异步测试。

test "getting config variables" do
  Application.put_env(:appname, :app_id, "123")
  assert Auth.app_id === "123"
end

test "getting env variables" do
  System.put_env("APPNAME_APP_ID", "111")
  assert Auth.app_id === "111"
end

这是 getter 函数内部的样子:

def app_id do
  Application.get_env(
    :appname,
    :app_id,
    System.get_env("APPNAME_APP_ID")
  )
end

问题是我有很多使用这些 getter 的函数,比如返回带有 app_id 作为参数的 url。

【问题讨论】:

  • 我知道这是一个令人毛骨悚然的细节,但那些并不是真正的“吸气剂”。不是 OO 意义上的。事实上,您可以概括 app_id 函数,方法是不隐藏其中的细节,而是将值作为参数进行检索。

标签: elixir


【解决方案1】:

没有办法绕过这些变量是全局的事实(不考虑模拟)。我的建议是不要同时运行测试(不要在 use ExUnit 中使用 async: true)或者不要测试 app_id/0 函数(因为无论如何它都很简单)。

【讨论】:

  • 问题是这些getter被很多函数使用,我试图让我的所有测试保持异步。 José Valim 有一个反对使用嘲讽的好观点,但没有它们,这似乎是一个死胡同......
  • @Skylight 我的建议仍然是不要测试该功能,因为它非常微不足道(没有参数,非常小的身体,非常可预测的行为)。模拟这样的功能是 IMO 的开销。如果这个函数被很多函数使用,那么其中的错误可能无论如何都会弹出:)
  • @Skylight 我同意whatyouhide。测试这种小而琐碎的功能有点像货物崇拜工程。把时间花在更重要的问题上。
【解决方案2】:

正如@whatyouhide 所说,您无法绕过这些变量是全局变量的事实,所以我要做的就是隔离问题:

  • 使用async: falseapp_id 测试隔离在他们自己的测试文件中,并按照您已经这样做的方式进行测试;
  • 对结果真正取决于app_id 值的所有测试执行相同操作;
  • 对于所有使用app_idapp_id 的实际值不会影响结果的测试,请在setup_all 回调中设置一个合理的值,以便为整个测试文件设置一次。

这样,您的大多数测试都可以异步运行,只有结果直接依赖于app_id 值的测试才能以非异步方式运行。

【讨论】:

    【解决方案3】:

    我也遇到过类似的情况,最后用了这样的东西:

    defmodule MyApp.ConfigTest do
      use ExUnit.Case, async: false
    
      setup do
        previous_env = System.get_env()
        on_exit(fn -> System.put_env(previous_env) end)
      end
    
      test "I can change environment for this test only" do
        System.put_env("HOME", "/tmp")
        assert System.get_env("HOME") == "/tmp"
      end
    
      test "Should not affect other tests" do
        assert System.get_env("HOME") != "/tmp"
      end
    end
    

    重要的东西是 on_exit 回调和 async: false 定义。

    我不是 100% 确定它是安全的,甚至是漂亮的 TBH。

    【讨论】:

      【解决方案4】:

      你可以做的是编写 shell 代码来调用测试。编写设置环境变量的 shell 代码,然后执行测试。您的 shell 代码可以使用 sed 或类似的东西来修改 config.exs 以根据您希望测试的方式具有或不具有该值。

      就目前而言,这些测试几乎没有增加任何价值。现在您正在有效地测试Application 模块。

      如果未设置任何位置(config.exs 或环境变量),也不要忘记测试您的代码。

      【讨论】:

        【解决方案5】:

        如果您使用的是Mock framework,您可以执行以下操作。

        defmodule MyApp.ConfigTest do
          use ExUnit.Case, async: false
          import Mock
        
          test "I can change specific environment for this test only" do
              env = System.get_env()
              with_mock(System, [:passthrough],
                get_env: fn
                  "HOME" -> "/tmp"
                  key -> Map.get(env, key)
                end
              ) do
             assert System.get_env("HOME") == "/tmp"
          end
        
          test "Should not affect other tests" do
            assert System.get_env("HOME") != "/tmp"
          end
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-14
          • 2016-07-03
          • 2013-06-17
          • 2018-06-05
          • 1970-01-01
          • 2012-07-03
          相关资源
          最近更新 更多