混合简介

在本指南中,我们将学习如何使用自己的监督树,配置,测试等来构建完整的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构建健壮的容错应用程序。在本章中,我们将探讨OTP与Elixir结合的方面,包括监督树,活动经理等;
  • Mix是一个随Elixir一起提供的构建工具,提供创建,编译,测试应用程序,管理其依赖关系等等的任务;
  • ExUnit是一个与Elixir一起提供的基于测试单元的框架;在本章中,我们将使用Mix创建我们的第一个项目,并探讨OTP,Mix和ExUnit中的不同功能。本指南需要Elixir v1.5.0或更高版本。您可以按照入门指南第一章中所述elixir --version的步骤,根据需要检查Elixir版本并安装更新版本。如果您对本指南有任何疑问或改进,请通过 Elixir论坛问题跟踪器等讨论渠道进行讨论。您的意见非常重要,可以帮助我们保证指南的可访问性和最新性!本指南的最终代码位于此存储库中并可以作为参考。Elixir指南也以EPUB格式提供:

我们的第一个项目

当您安装Elixir,除了获得elixirelixirciex可执行文件,您还可以获得一个名为可执行脚本Elixirmix

让我们通过mix new从命令行调用来创建我们的第一个项目。我们将传递项目名称作为参数(kv在这种情况下),并告诉Mix,我们的主模块应该是全大写的KV,而不是默认的,这应该是Kv

$ 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,您需要在PATH中同时包含可执行文件mixelixir可执行文件。这就是安装Elixir时会发生的情况。

项目编译

mix.exs我们的新项目文件夹(kv)中生成了一个名为文件的文件,其主要职责是配置我们的项目。我们来看看它:

defmodule KV.Mixfile do
  use Mix.Project

  def project do
    [
      app: :kv,
      version: "0.1.0",
      elixir: "~> 1.6-dev",
      start_permanent: Mix.env == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
    ]
  end
end

我们mix.exs定义了两个公共函数:project返回项目名称和版本等项目配置,以及application用于生成应用程序文件的项目配置。

还有一个名为的私有函数deps,它从project函数中调用,它定义了我们的项目依赖关系。deps不需要定义为单独的功能,但它有助于保持项目配置的整洁。

Mix还会在lib/kv.ex一个包含一个函数的模块中生成一个文件,该文件名为hello

defmodule KV do
  @moduledoc """
  Documentation for KV.
  """

  @doc """
  Hello world.

  ## Examples

      iex> KV.hello
      :world

  """
  def hello do
    :world
  end
end

这个结构足以编译我们的项目:

$ cd kv
$ mix compile

将产出:

Compiling 1 file (.ex)
Generated kv app

lib/kv.ex文件已编译,kv.app生成了一个名为的应用程序清单,并按照“入门指南”中的说明合并了所有协议。所有编译工件都_build使用mix.exs文件中定义的选项放置在目录中。

项目编译完成后,您可以iex运行以下命令在项目中启动会话:

$ iex -S mix

运行测试

Mix还为运行我们的项目测试生成了适当的结构。混合项目通常遵循目录中每个文件在目录中具有<filename>_test.exs文件的约定。出于这个原因,我们已经可以找到对应于我们的文件。在这一点上它并没有太多的作用:testlibtest/kv_test.exslib/kv.ex

defmodule KVTest do
  use ExUnit.Case
  doctest KV

  test "greets the world" do
    assert KV.hello() == :world
  end
end

重要的是要注意几件事情:

  1. 测试文件是一个Elixir脚本文件(.exs)。这很方便,因为我们不需要在运行它们之前编译测试文件;
  1. 我们定义一个名为test module KVTest,用于ExUnit.Case注入测试API并使用test/2宏定义一个简单的测试;

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

ExUnit.start()

在我们运行测试之前,每次都需要这个文件。我们可以运行测试mix test

Compiled lib/kv.ex
Generated kv app
..

Finished in 0.04 seconds
2 tests, 0 failures

Randomized with seed 540224

请注意,通过运行mix test,Mix已经编译了源文件并再次生成了应用程序清单。这是因为Mix支持多种环境,我们将在下一节中探讨。

此外,您可以看到ExUnit为每个成功的测试打印一个点,并自动随机测试。让我们让测试失败并看看会发生什么。

将断言更改test/kv_test.exs为以下内容:

assert KV.hello() == :oops

现在再次运行mix test(注意这次不会有编译):

  1) test greets the world (KVTest)
     test/kv_test.exs:5
     Assertion with == failed
     code:  assert KV.hello() == :oops
     left:  :world
     right: :oops
     stacktrace:
       test/kv_test.exs:6: (test)

.

Finished in 0.05 seconds
2 tests, 1 failure

对于每次故障,ExUnit都会打印一份详细报告,其中包含测试用例的测试名称,失败的代码以及==操作员左侧和右侧(rhs)的值。

在失败的第二行中,正好位于测试名称下方,有测试定义的位置。如果您完整地复制测试位置(包括文件和行号)并将其附加到mix test,则Mix将加载并运行该特定测试:

$ mix test test/kv_test.exs:5

这个快捷方式在构建我们的项目时非常有用,它允许我们通过运行单个测试来快速迭代。

最后,堆栈跟踪与失败本身相关,提供有关测试的信息以及经常从源文件中生成失败的位置。

环境

Mix支持“环境”的概念。它们允许开发人员为特定场景自定义编译和其他选项。默认情况下,Mix理解三种环境:

  • :dev- Mix任务(比如compile)默认运行的那个
  • :test-被mix test
  • :prod - 您将用于在生产中运行项目的人员

该环境仅适用于当前项目。正如我们稍后会看到的那样,添加到项目中的任何依赖项都将默认在:prod环境中运行。

每环境定制可以通过访问来完成Mix.env功能,在你的mix.exs文件,它返回当前环境作为一个原子。这就是我们在:start_permanent选项中使用的:

def project do
  [...,
   start_permanent: Mix.env == :prod,
   ...]
end

如果为true,则该:start_permanent选项将以永久模式启动应用程序,这意味着如果应用程序的监督树关闭,Erlang VM将崩溃。请注意,我们不希望在开发和测试中发生此行为,因为为了进行故障排除,保持VM实例在这些环境中运行非常有用。

:dev除了默认为环境的test任务外,混合将默认为:test环境。环境可以通过MIX_ENV环境变量进行更改:

$ MIX_ENV=prod mix compile

或在Windows上:

> set "MIX_ENV=prod" && mix compile

Mix是一个构建工具,因此,它并不总是在生产中可用,特别是如果您的团队使用明确的构建步骤。因此,建议Mix.env仅在配置文件和内部进行访问mix.exs,而不要在应用程序代码(lib)中进行访问。

探索

Mix还有很多,我们将在建设项目时继续探索它。一个总体概述可在混合文档上

请记住,您始终可以调用帮助任务来列出所有可用的任务:

$ mix help

您可以通过调用获得有关特定任务的更多信息mix help TASK

我们来写一些代码吧!