簡體   English   中英

測試Elixir / Phoenix服務模塊

[英]Testing Elixir/Phoenix Service modules

我一直在玩Elixir / Phoenix第三方模塊。 (用於從第三方服務獲取某些數據的模塊)這些模塊之一如下所示:

module TwitterService do
  @twitter_url "https://api.twitter.com/1.1"

  def fetch_tweets(user) do
     # The actual code to fetch tweets
     HTTPoison.get(@twitter_url)
     |> process_response
  end      

  def process_response({:ok, resp}) do
    {:ok, Poison.decode! resp}
  end

  def process_response(_fail), do: {:ok, []}
end

實際數據對我的問題無關緊要。 因此,現在,我對如何在測試中動態配置@twitter_url模塊變量感興趣,以使某些測試故意失敗。 例如:

module TwitterServiceTest
  test "Module returns {:ok, []} when Twitter API isn't available"
    # I'd like this to be possible ( coming from the world of Rails )
    TwitterService.configure(:twitter_url, "new_value") # This line isn't possible
    # Now the TwiterService shouldn't get anything from the url
    tweets = TwitterService.fetch_tweets("test")
    assert {:ok, []} = tweets
  end
end

我該如何實現? 注意:我知道我可以在devtest環境中使用:configs分別配置@twiter_url ,但是我也希望能夠對Twitter API的真實響應進行測試,這將更改整個測試的URL。環境。
我想到的解決方案之一是

def fetch_tweets(user, opts \\ []) do
  _fetch_tweets(user, opts[:fail_on_test] || false)
end

defp _fetch_tweets(user, [fail_on_test: true]) do
  # Fails
end

defp _fetch_tweets(user, [fail_on_test: false]) do
  # Normal fetching
end

但這似乎有點駭人聽聞和愚蠢,必須對此有一個更好的解決方案。

正如Jose在Mocks And Explicit Contracts中建議的那樣,最好的方法可能是使用依賴項注入:

module TwitterService do
  @twitter_url "https://api.twitter.com/1.1"

  def fetch_tweets(user, service_url \\ @twitter_url) do
     # The actual code to fetch tweets
     service_url
     |> HTTPoison.get()
     |> process_response
  end      

  ...
end

現在在測試中,您僅在必要時注入另一個依賴項:

# to test against real service
fetch_tweets(user)

# to test against mocked service
fetch_tweets(user, SOME_MOCK_URL)

這種方法還將使將來更容易插入其他服務。 假定服務遵循某種約定(在這種特殊情況下,給定url的json響應),則處理器的實現不應依賴於其基礎服務。

config聽起來這里是個好方法。 您可以在運行時在測試中修改配置中的值,然后在測試后將其還原。

首先,在您的實際代碼中,而不是@twitter_url ,請使用Application.get_env(:my_app, :twitter_url)

然后,在測試中,可以使用如下包裝函數:

def with_twitter_url(new_twitter_url, func) do
  old_twitter_url = Application.get_env(:my_app, :twitter_url)
  Application.set_env(:my_app, :twitter_url, new_twitter_url)
  func.()
  Application.set_env(:my_app, :twitter_url, old_twitter_url)
end

現在在您的測試中,執行以下操作:

with_twitter_url "<new url>", fn ->
  # All calls to your module here will use the new url.
end

確保您沒有為此使用異步測試,因為此技術會修改全局環境。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM