1-Mix簡介

StraightDave發表於2014-10-11

1-Mix簡介

第一個應用程式
工程的編譯
執行測試
環境
探索

在這份指導手冊中,我們將學習建立一個完整的Elixir應用程式,以及它自己的監督樹、配置、測試等等內容。

這個程式是一個分散式的鍵-值資料庫。我們會把鍵-值儲存在“桶”中,分佈儲存到多個節點。我們還會建立一個簡單的客戶端工具,讓我們可以連線任意一個節點,並且能夠傳送類似以下的命令:

CREATE shopping
OK

PUT shopping milk 1
OK

PUT shopping eggs 3
OK

GET shopping milk
1
OK

DELETE shopping eggs
OK

為了編寫這樣的程式,我們將用到一下三個主要工具:

  • OTP是一個隨Erlang釋出的程式碼庫的集合。Erlang開發者使用OTP來建立健壯的、高度容錯的程式。在本章中,我們將來探索與Elixir整合在一起的OTP,包括監督樹、事件管理等等;
  • Mix是隨Elixir釋出的構建工具,用來建立、編譯、測試你的應用程式,還可以用來管理依賴等;
  • ExUnit是一個隨Elixir釋出的單元測試工具

本章我們就是要用Mix來建立我們第一個工程,探索OTP,Mix以及ExUnit的各種特性。

注意:本手冊需要Elixir v0.15.0或以上。你可以使用命令elixir -v檢視版本。如果需要,可以按照《Elixir入門》第一章節安裝最新的版本。

1.1-第一個應用程式

當你安裝Elixir時,你不僅得到了elixirelixirciex命令,還得到了一個可執行的Elixir指令碼叫做mix

從命令列輸入mix new命令來建立我們的第一個工程。我們需要傳遞工程名稱作為引數(在這裡,kv),然後告訴mix我們的主模組的名字是全大寫的KV,否則按照預設,mix會建立一個主模組,名字是第一個字母大寫的工程名稱(Kv。因為K和V在含義上是平等關係,所以最好是都大寫)。

$ mix new kv --module KV

Mix將建立一個資料夾名叫kv,裡面有一些檔案:

* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/kv.ex
* creating test
* creating test/test_helper.exs
* creating test/kv_test.exs

現在簡單看看這些建立的檔案。

注意:Mix是一個Elixir可執行指令碼。這意味著,你要想用mix為名直接呼叫它,需要提前將Elixir目錄放進系統的環境變數中。否則,你需要使用elixir來執行mix:

$ bin/elixir bin/mix new kv --module KV

你可以用-S選項來執行,它不管你有沒有把Elixir目錄加入環境變數:

$ bin/elixir -S mix new kv --module KV

1.2-工程的編譯

一個名叫mix.exs的檔案會被自動建立在工程目錄中。它的主要工作是配置你的工程。看看它的內容(略去註釋):

defmodule KV.Mixfile do
  use Mix.Project

   def project do
    [app: :kv,
     version: "0.0.1",
     deps: deps]
  end

  def application do
    [applications: [:logger]]
  end

  defp deps do
    []
  end
end

我們的mix.exs定義了兩個公共函式:project,它返回工程的配置資訊如工程名稱和版本;application,它用來生成應用程式檔案。

還有一個私有函式叫做deps,它被project函式呼叫,裡面定義了工程的依賴。不一定非要把deps定義為一個獨立的函式,但是這樣做可以使工程的配置檔案看起來更整齊。

Mix還生成了檔案lib/kv.ex,內容是個簡單的模組定義:

defmodule KV do
end

以上這個結構就足以編譯我們的工程了:

$ mix compile

將生成:

Compiled lib/kv.ex
Generated kv.app

注意檔案lib/kv.ex被編譯,生成了檔案kv.app。這個.app檔案是根據配置檔案mix.exsapplication/0函式的資訊編譯出來的。我們之後會詳細介紹配置檔案。

一旦工程被編譯成功,便可以從工程目錄啟動一個iex會話來執行:

$ iex -S mix

1.3-執行測試

Mix還生成了合適的結構用以測試我們的工程。在test目錄中,測試檔案一般以<filename>_test.exs模式命名,每一個對應一個lib目錄中的檔名。我們以及有了測試lib/kv.ex所需的test/kv_test.exs檔案。目前它幾乎什麼也沒做:

defmodule KVTest do
  use ExUnit.Case

  test "the truth" do
    assert 1 + 1 == 2
  end
end

需要注意幾點:

  1. 測試檔案使用的副檔名(.exs)意為Elixir指令碼檔案。這很方便,我們不用為每次測試檔案的改動而編譯一次。
  2. 我們定義了一個測試模組名為KVTest,它用ExUnit.Case來注入測試API,並使用巨集test/2定義了一個簡單的測試;

Mix還生成了一個檔名叫test/test_helper.exs,它負責設定測試框架:

ExUnit.start

每次Mix執行測試時,這個檔案將自動被匯入(required)。執行測試,使用命令mix test

Compiled lib/kv.ex
Generated kv.app
.

Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 tests, 0 failures

Randomized with seed 540224

注意在執行mix test時,Mix會重新編譯原始檔,再次生成新的應用程式。這涉及到Mix的執行環境,我們稍後章節會詳細介紹。

另外,ExUnit為每一個成功的測試結果列印一個點,它還會自動隨機安排測試順序。讓我們把測試改成失敗看看。 修改test/kv_test.exs裡面的斷言,改成:

assert 1 + 1 == 3

現在再次執行mix test(注意,沒有編譯行為發生):

1) test the truth (KVTest)
   test/kv_test.exs:4
   Assertion with == failed
   code: 1 + 1 == 3
   lhs:  2
   rhs:  3
   stacktrace:
     test/kv_test.exs:5

Finished in 0.05 seconds (0.05s on load, 0.00s on tests)
1 tests, 1 failures

為每一個測試失敗,ExUnit列印一個詳細的報告,包含了測試名稱,失敗的程式碼,失敗斷言中==號的左值和右值。

在錯誤提示的第二行,測試名稱右邊,是測試定義的位置。將這個位置作為引數給mix test命令,將僅僅執行那段測試程式碼:

$ mix test test/kv_test.exs:4

最後是關於錯誤的追蹤棧資訊,給出關於測試的額外資訊,包括測試失敗的地方,還有原檔案中產生失敗的程式碼位置等。

1.4-環境

Mix支援“環境”的概念。它允許開發者為某些場景定義不同的編譯或是其它動作。預設地,Mix理解三種環境:

  • :dev - Mix的預設環境(編譯等操作)
  • :test - mix test使用的環境
  • :prod - 用來將應用程式釋出到產品環境

注意:如果你向工程中新增了依賴,它們都不會使用你工程的環境,而是使用它們的:prod環境的設定!

預設情況下,這些環境行為都差不多,我們目前為止寫的配置檔案對它們都有效。 為某個特別的環境定義不同的配置,需要編寫mix.exs檔案中的Mix.env函式,它會以原子形式返回當前的環境:

def project do
  [deps_path: deps_path(Mix.env)]
end

defp deps_path(:prod), do: "prod_deps"
defp deps_path(_), do: "deps"

Mix預設使用:dev環境,除非在執行測試時使用的是:test環境。環境可以隨時更改:

$ MIX_ENV=prod mix compile

1.5-探索

關於Mix,內容還有很多,我們在編寫這個工程的過程中還會陸續接觸到一些。可以參考Mix的概覽

記住,你可以使用幫助來獲取你需要的資訊,如:

$ mix help TASK