1-Mix简介

    在这份指导手册中,我们将学习创建一个完整的Elixir应用程序,以及监督树、配置、测试等高级概念。

    这个程序是一个分布式的键-值存储数据库。我们会把键-值存储在“桶”中,分布存储到多个节点。
    我们还会创建一个简单的客户端工具,可以连接任意一个节点,并且能够发送类似以下的命令:

    为了编写这个程序,我们将主要用到以下三个工具:

    • OTP(Open Telecom Platform)
      OTP是一个随Erlang发布的代码库集合。Erlang开发者使用OTP来创建健壮的、高度容错的程序。在本章中,我们将来探索与Elixir整合在一起的OTP,包括监督树、事件管理等等;

    • Mix
      Mix是随Elixir发布的构建工具,用来创建、编译、测试你的应用程序,还可以用来管理依赖等;

    • ExUnit
      ExUnit是一个随Elixir发布的单元测试工具

    本章会用Mix来创建我们第一个工程,探索OTP、Mix以及ExUnit的各种特性。

    当你安装Elixir时,你不仅得到了elixirelixirciex命令,
    还得到一个可执行的Elixir脚本叫做mix

    从命令行输入mix new命令来创建我们的第一个工程。
    我们需要传递工程名称作为参数(在这里,比如叫做 kv),
    然后告诉mix我们的主模块的名字是全大写的KV
    否则按照默认,mix会创建一个主模块,名字是第一个字母大写的工程名称(Kv)。
    因为K和V的含义在我们的程序中上是平等关系,所以最好是都用大写:

    1. $ mix new kv --module KV

    Mix将创建一个文件夹名叫kv,里面有一些文件:

    1. * creating README.md
    2. * creating .gitignore
    3. * creating mix.exs
    4. * creating config
    5. * creating config/config.exs
    6. * creating lib
    7. * creating lib/kv.ex
    8. * creating test
    9. * creating test/test_helper.exs
    10. * creating test/kv_test.exs

    现在简单看看这些创建的文件。

    一个名叫mix.exs的文件会被自动创建在工程目录中。
    它的主要作用是配置你的工程。它的内容如下(略去代码中的注释):

    1. defmodule KV.Mixfile do
    2. use Mix.Project
    3. def project do
    4. [app: :kv,
    5. version: "0.0.1",
    6. elixir: "~> 1.2",
    7. start_permanent: Mix.env == :prod,
    8. deps: deps]
    9. end
    10. def application do
    11. [applications: [:logger]]
    12. end
    13. defp deps do
    14. []
    15. end

    我们的mix.exs定义了两个公共函数:
    一个是project,它返回工程的配置信息,如工程名称和版本;
    另一个是application,它用来生成应用程序文件。

    还有一个私有函数叫做deps,它被project函数调用,里面定义了工程的依赖。
    不一定非要把deps定义为一个独立的函数,但是这样做可以使工程的配置文件看起来整洁美观。

    Mix还生成了文件lib/kv.ex,其内容是个简单的模块定义:

    以上这个结构就足以编译我们的工程了:

    1. $ cd kv
    2. $ mix compile

    将生成:

    1. Compiled lib/kv.ex
    2. Generated kv app
    3. Consolidated List.Chars
    4. Consolidated Collectable
    5. Consolidated String.Chars
    6. Consolidated Enumerable
    7. Consolidated IEx.Info
    8. Consolidated Inspect

    注意文件lib/kv.ex被编译,生成了程序manifest文件:kv.app
    及一些 协议(参考入门手册)。根据mix.exs的配置,所有编译产出被放在_build目录中。

    一旦工程被编译成功,便可以从工程目录启动一个iex会话:

    1. $ iex -S mix

    Mix还生成了合适的文件结构,来测试我们的工程。Mix工程一般沿用一些命名规则:
    test目录中,测试文件一般以<filename>_test.exs模式命名。
    每一个<filename>对应一个lib目录中的文件名。
    根据这个命名规则,我们已经有了测试lib/kv.ex所需的test/kv_test.exs文件。
    只是目前它几乎什么也没做:

    1. defmodule KVTest do
    2. use ExUnit.Case
    3. doctest KV
    4. test "the truth" do
    5. end
    6. end

    需要注意几点:

    1. 测试文件使用的扩展名(.exs)即Elixir脚本文件。这很方便,我们不用在跑测试前还编译一次。
    2. 我们定义了一个测试模块名为KVTest,用ExUnit.Case来注入测试API,
      并使用宏test/2定义了一个简单的测试;

    Mix还生成了一个文件名叫test/test_helper.exs,它负责设置测试框架:

    每次Mix执行测试时,这个文件将自动被导入(required)。执行测试,使用命令mix test

    注意,每次运行mix test时,Mix会重新编译源文件,生成新的应用程序。
    这是因为Mix支持多套执行环境,我们稍后章节会详细介绍。

    1. assert 1 + 1 == 3

    现在再次运行mix test(注意这次没有编译行为发生):

    1. 1) test the truth (KVTest)
    2. test/kv_test.exs:5
    3. Assertion with == failed
    4. code: 1 + 1 == 3
    5. lhs: 2
    6. rhs: 3
    7. stacktrace:
    8. test/kv_test.exs:6
    9. Finished in 0.05 seconds (0.05s on load, 0.00s on tests)
    10. 1 tests, 1 failures

    ExUnit会为每个失败的测试结果打印一个详细的报告。其内容包含了测试名称,失败的代码,
    失败断言中==号的左值(lhs)和右值(rhs)。

    在错误提示的第二行(测试名称下面那行),是该测试的代码位置。
    将这个位置作为参数给mix test命令,则将仅执行该条测试:

    1. $ mix test test/kv_test.exs:5

    这个十分有用是吧。

    最后是关于错误的追踪栈信息,给出关于测试的额外信息。
    包括测试失败的地方,还有原文件中产生失败的具体位置等。

    Mix支持“环境”的概念。它允许开发者为某些场景定义不同的编译等动作。
    默认地,Mix理解三种环境:

    • :dev - Mix任务的默认执行环境(如编译等操作)
    • :test - mix test使用的环境
    • :prod - 用来将应用程序发布到产品环境

    环境配置只对当前工程有效。我们之后会看到,向工程中添加的依赖默认在:prod环境下工作。

    可以通过访问mix.exs工程配置文件中的Mix.env函数定义不同的环境配置,
    它会以原子形式返回当前的环境。
    比如我们用之于:build_embedded:start_permanent:这两个选项:

    1. def project do
    2. [...,
    3. build_embedded: Mix.env == :prod,
    4. start_permanent: Mix.env == :prod,
    5. ...]
    6. end

    上面代码的含义就是程序在:prod环境中运行的话,则使用那两个选项。

    当你编译代码的时候,Elixir把编译产出都置于_build目录。
    但是,有些时候Elixir为了避免一些不必要的复制操作,
    会在_build目录中创建一些链接指向特定文件而不是copy。
    :build_embedded选项被设置为true时可以制止这种行为,
    从而在_build目录中提供执行程序所需的所有文件。

    类似地,当:start_permanent选项设置为true的时候,程序会以“Permanent模式”执行。
    意思是如果你的程序的监督树挂掉,Erlang虚拟机也会挂掉。
    注意在:dev和:test环境中,我们可能不需要这样的行为。
    因为在这些环境中,为了troubleshooting等目的,需要保持虚拟机持续运行。

    Mix默认使用:dev环境,除非在执行测试时需要用到:test环境。
    环境可以随时更改:

    或在Windows上:

    记住,你可以使用mix的帮助信息来帮助理解一些任务的操作方法,如: