我对Elixir和函数式编程都比较陌生,我很难正确地对由其他函数组成的函数进行单元测试。通常的问题是:当我有一个使用其他函数g、h等的函数f时,应该采用哪种方法来测试整个函数呢?
从面向对象编程的世界中出发,首先想到的方法是注入与f有关的函数。我可以单元测试g、h等函数,并将它们作为参数注入f。然后,f的单元测试只需要确保按预期调用这些被注入的函数即可。但这种做法感觉过度拟合了,并且对于函数组合应该是一件便宜的事情以及你不应该在整个代码库中传递所有这些参数的函数式思维方式来说,是一种总体上繁琐的做法。
我也可以将g、h等函数以及f视为黑盒进行单元测试,这样感觉是正确的做法,但是f的复杂度会急剧增加。编写简单可扩展的测试是单元测试的主要目的之一。
为了更具体地说明这一观点,我会放置一个将其他函数组合在内的函数的例子,并且我不知道如何正确地进行单元测试。特别的,这段代码是用于RESTful风格下资源的创建的插件,注意一些“依赖项”是纯函数(例如validate_account_admin),但其他则不是(Providers.create)。
从面向对象编程的世界中出发,首先想到的方法是注入与f有关的函数。我可以单元测试g、h等函数,并将它们作为参数注入f。然后,f的单元测试只需要确保按预期调用这些被注入的函数即可。但这种做法感觉过度拟合了,并且对于函数组合应该是一件便宜的事情以及你不应该在整个代码库中传递所有这些参数的函数式思维方式来说,是一种总体上繁琐的做法。
我也可以将g、h等函数以及f视为黑盒进行单元测试,这样感觉是正确的做法,但是f的复杂度会急剧增加。编写简单可扩展的测试是单元测试的主要目的之一。
为了更具体地说明这一观点,我会放置一个将其他函数组合在内的函数的例子,并且我不知道如何正确地进行单元测试。特别的,这段代码是用于RESTful风格下资源的创建的插件,注意一些“依赖项”是纯函数(例如validate_account_admin),但其他则不是(Providers.create)。
def call(conn, _opts) do
account_uuid = conn.assigns.current_user.account["uuid"]
with {:ok, conn} <- Http.Authorization.validate_account_admin(conn),
{:ok, form_data} <- Http.coerce_form_data(conn, FormData),
{:ok, provider} <- Providers.create(FormData.to_provider(form_data), account_uuid: account_uuid) do
Http.respond_create(conn, Http.provider_path(provider))
else
{:error, reason, messages} -> Http.handle_error(conn, reason, messages)
end
end
谢谢!