首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ecto的单元测试插入的数据在哪里?

ecto的单元测试插入的数据在哪里?
EN

Stack Overflow用户
提问于 2022-09-06 08:33:26
回答 1查看 151关注 0票数 1

我模仿了hexpm项目来编写与回购相关的单元测试。

但是重复的insert操作总是成功的,assert :error失败。

断言错误消息如下:

代码语言:javascript
运行
复制
macbook:pen yuchen$ mix test
   
 ...
    
      1) test username and email are unique (Pen.Account.UserTest)
         test/pen/accounts/user_test.exs:39
         match (=) failed
         code:  assert {:error, changeset} =
                  User.build(%{
                    name: "some_other_username",
                    email: "some_other_email@example.com",
                    password: "password"
                  })
                  |> insert()
         left:  {:error, changeset}
         right: {
                  :ok,
                  %Pen.Accounts.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">, email: "some_other_email@example.com", id: 170, inserted_at: ~U[2022-09-06 08:08:35.902874Z], name: "some_other_username", password: "$2b$12$M1S.X2GmnGD/uASom2v01OYwdihE7sVbp4YY5mZAwgY9ITPMYdgzu", updated_at: ~U[2022-09-06 08:08:35.902874Z]}
                }
         stacktrace:
           test/pen/accounts/user_test.exs:54: (test)
    
    .
    
    Finished in 1.9 seconds (1.7s async, 0.1s sync)
    5 tests, 1 failure

我的单元测试代码如下:

代码语言:javascript
运行
复制
defmodule Pen.Account.UserTest do
  use Pen.DataCase, async: true
  require Logger

  alias Pen.Accounts.{Auth, User}

  setup do
    {:ok,user} = insert(%User{password: Auth.gen_password("password")})
    %{user: user, password: "password"}
  end

  describe "build/2" do
    test "builds user" do
      changeset =
        User.build(%{
          name: "username",
          email: "mail@example.com",
          password: "password"
        })

      assert changeset.valid?
    end
  end

  # test "validates username" do
  #   changeset = User.build(%{name: "x"})
  #   assert errors_on(changeset)[:name] == ["should be at least 3 character(s)"]

  #   changeset = User.build(%{name: "{€%}"})
  #   assert errors_on(changeset)[:name] == ["has invalid format"]
  # end

  # test "validates password" do
  #   changeset = User.build(%{password: "x"})
  #   assert errors_on(changeset)[:password] == ["should be at least 7 character(s)"]
  # end

  test "username and email are unique", %{user: user} do
    assert {:ok, changeset} =
             (User.build(
               %{
                 name: user.name,
                 email: "some_other_email@example.com",
                 password: "password"
               }
              #  ,
              #  true
             )
             |> insert())
    Logger.debug("first: #{inspect changeset}")
    # assert errors_on(changeset)[:name] == ["has already been taken"]

    assert {:error, changeset} =
             (User.build(
               %{
                 name: "some_other_username",
                 email: "some_other_email@example.com",
                 password: "password"
               }
             )
             |> insert())

    assert errors_on(changeset)[:email] == "already in use"
    # end
  end

使用沙箱,数据酶代码如下:

代码语言:javascript
运行
复制
defmodule Pen.DataCase do
  @moduledoc """
  This module defines the setup for tests requiring
  access to the application's data layer.

  You may define functions here to be used as helpers in
  your tests.

  Finally, if the test case interacts with the database,
  we enable the SQL sandbox, so changes done to the database
  are reverted at the end of every test. If you are using
  PostgreSQL, you can even run database tests asynchronously
  by setting `use Pen.DataCase, async: true`, although
  this option is not recommended for other databases.
  """

  use ExUnit.CaseTemplate

  using do
    quote do
      # alias Pen.Repo
      import Pen.Repo

      import Ecto
      import Ecto.Changeset
      import Ecto.Query
      import Pen.DataCase
    end
  end

  setup tags do
    Pen.DataCase.setup_sandbox(tags)
    :ok
  end

  @doc """
  Sets up the sandbox based on the test tags.
  """
  def setup_sandbox(tags) do
    pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Pen.Repo, shared: not tags[:async])
    on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
  end

  @doc """
  A helper that transforms changeset errors into a map of messages.

      assert {:error, changeset} = Accounts.create_user(%{password: "short"})
      assert "password is too short" in errors_on(changeset).password
      assert %{password: ["password is too short"]} = errors_on(changeset)

  """
  def errors_on(changeset) do
    Ecto.Changeset.traverse_errors(changeset, fn {message, opts} ->
      Regex.replace(~r"%{(\w+)}", message, fn _, key ->
        opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string()
      end)
    end)
  end
end

我已经检查过postgres db,用户表记录在每个单元测试之后都不会增加。

代码语言:javascript
运行
复制
 id | name |            email             |                           password                           |     inserted_at     |     updated_at      
----+------+------------------------------+--------------------------------------------------------------+---------------------+---------------------
  1 |      |                              | $2b$12$hw0fBhi7PtcjVdXRocxnReaToBe.IyeFZa7qvRolU2ymdgcmFbufW | 2022-09-06 05:47:41 | 2022-09-06 05:47:41

用户迁移情况如下:

代码语言:javascript
运行
复制
defmodule Pen.Repo.Migrations.CreateUsers do
  use Ecto.Migration

  def change do
    create table(:users) do
      add :name, :string
      add :email, :string
      add :password, :string

      timestamps()

    end
    create unique_index(:users, [:name],[unique: true])
    create unique_index(:users, [:email],[unique: true])
  end
end

postgres用户的结构如下:

代码语言:javascript
运行
复制
                                          Table "public.users"
   Column    |              Type              | Collation | Nullable |              Default              
-------------+--------------------------------+-----------+----------+-----------------------------------
 id          | bigint                         |           | not null | nextval('users_id_seq'::regclass)
 name        | character varying(255)         |           |          | 
 email       | character varying(255)         |           |          | 
 password    | character varying(255)         |           |          | 
 inserted_at | timestamp(0) without time zone |           | not null | 
 updated_at  | timestamp(0) without time zone |           | not null | 
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "users_email_index" UNIQUE, btree (email)
    "users_name_index" UNIQUE, btree (name)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-07 09:55:01

Ecto通常配置为使用不同的数据库进行开发和测试(分别在config/dev.exsconfig/test.exs中定义)。

每当您修改已经运行的现有迁移(例如,在您仍在调整模式时添加唯一索引或字段),Ecto将不会自动重新运行此迁移。你需要跑:

  • mix ecto.reset修复dev DB
  • MIX_ENV=test mix ecto.reset以修复测试DB

如果忘记运行后者,则可能会为测试DB提供不同的表定义。

此外,值得一提的是,通常用于测试的Ecto.Adapters.SQL.Sandbox模块将每个测试包装在一个事务中,并在最后回滚所有的内容。这是一种非常强大的机制,允许您保持测试的独立性和隔离性,并且仍然并行运行它们,但这意味着在运行测试之后不会填充测试DB中的表。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73619010

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档