Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >ecto的单元测试插入的数据在哪里?

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

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

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

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

断言错误消息如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
 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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
                                          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 01: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

复制
相关文章
C++中变量声明与定义的规则
为了支持分离式编译,C++将定义和声明区分开。其中声明规定了变量的类型和名字,定义除此功能外还会申请存储空间并可能为变量赋一个初始值。
TOMOCAT
2021/04/20
2.4K0
JavaScript-变量/函数声明提升
(1)如上定义了一个名为test的变量,但未给这个变量进行初始化(也就是没有赋值),此时其默认初始化值为 undefined。
WEBING
2019/03/13
1.1K0
JavaScript-变量/函数声明提升
Python变量的命名_python函数命名规则
变量名只有在第一次出现的时候,才是定义变量。当再次出现时,不是定义变量,而是直接使用之前定义的变量。
全栈程序员站长
2022/08/18
1.3K0
Python变量的命名_python函数命名规则
函数声明提升与变量提升
1.当在函数的作用域里定义一个和外部变量一样的名称的变量时,变量声明会提升至第一句,但是赋值则不变
Ewall
2018/09/04
7100
golang的变量声明
作者:matrix 被围观: 3 次 发布时间:2023-01-31 分类:Golang | 无评论 »
HHTjim 部落格
2023/02/13
1.1K0
PHP的变量范围
什么是变量的作用域?变量的作用域是指在脚本的一次生命周期内变量的有效范围。一般来说有全局和局部之分。 PHP中变量的作用域可以分为:超全局(全局变量的特殊类型,在局部范围里可直接使用),全局,局部,静态(是局部变量的特殊类型) 在PHP中,全局变量实际上是静态全局变量,如果不用unset显式的释放,那么等脚本运行结束全局变量才会被释放掉 局部静态变量细分可以是 局部静态函数变量(函数中声明的static变量),局部静态成员变量(类中声明的 static 属性,被所有类实例共享) 局部静态变量只有脚本运行结束才会被自动释放
luxixing
2019/05/29
1.9K0
Javascript基础:函数声明和变量声明提升之注意点函数优先
上面的代码会输出2019,而不是2020。新手同学们肯定会疑惑,为什么没有输出2020呢,因为2020赋值的那条语句是表达式而不是函数声明,因此不会被提升。
IT工作者
2022/01/26
6990
TypeScript 中的变量声明:变量声明的语法、变量的作用域、变量的类型推断和类型断言
TypeScript 是一种由微软开发的静态类型编程语言,它是 JavaScript 的超集,并且可以在编译时进行类型检查。在 TypeScript 中,变量声明是非常重要的一个概念,它定义了变量的名称和类型。通过正确地声明变量,我们可以增强代码的可读性、可维护性和可扩展性。本文将详细介绍 TypeScript 中的变量声明,包括变量声明的语法、变量的作用域、变量的类型推断和类型断言等内容。
网络技术联盟站
2023/07/06
8280
函数(三)(函数的声明)
如果在程序中自定义函数时,需要将被调函数定义在主调函数后面,就需要的函数调用之前加上函数原型声明。如果在函数调用之前既无函数定义,也无函数声明,编译时会出错。
pigeon
2022/04/11
6700
python关于变量的声明
s = "我是全局变量"def glo_and_non(): def do_local (): s = "我是局部变量" print ("1 "+ s) #在do_local中声明了一个局部变量s def do_nonlocal(): nonlocal s #在glo_and_non中声明的一个变量 s = "我不是局部,也不是全局" def do_global (): global s #声明的一个全局变量
常温阔乐
2022/11/18
2.6K1
go语言的变量声明
注意初始化器的个数必须与变量个数相同。 有初始化器时,变量类型可以省略,该变量的类型会根据初始化器自动推断。 例子:
梦飞
2022/06/23
1.1K0
简述python变量的命名规则_Python 变量命名规则
2.变量名只能是:数字,字母组成,不可以是空格或特殊字符,如:(#?。,¥$*~!&)等
全栈程序员站长
2022/09/06
1.7K0
TypeScript解决无法重新声明块范围变量“XXX”问题
在使用TypeScript开发项目时,在两个毫不相干的模块中定义相同变量tsLint会抛出:无法重新声明块范围变量“xxx”的错误
用户6256742
2022/07/06
3.4K0
TypeScript解决无法重新声明块范围变量“XXX”问题
【Python面试】 说说Python变量、函数、类的命名规则?
小猿会从最基础的面试题开始,每天一题。如果参考答案不够好,或者有错误的话,麻烦大家可以在留言区给出自己的意见和讨论,大家是要一起学习的 。
程序员小猿
2021/01/19
9390
【Python面试】 说说Python变量、函数、类的命名规则?
答:Python命名规范在编写代码中起到很重要的作用,虽然不遵循命名规范,程序可能也可以运行,但是使用命名规范可以更加直观地了解代码所代表的含义。
小小詹同学
2019/12/09
16.3K0
【Python面试】 说说Python变量、函数、类的命名规则?
js中的变量声明问题
从1,,2中我们可以看出js引擎是先对var声明的变量进行注册,再对函数类型的变量进行注册。 而3和4是一样的原理,js引擎执行到这段代码时,首先注册var a,但是此时的a的值是undefined,然后注册function a,然后开始执行语句a=1,所以输出的是number。
theanarkh
2019/03/06
4.4K0
[译] 方法是否应该在 T 或 *T 上声明
友情提示:此篇文章大约需要阅读 3分钟49秒,不足之处请多指教,感谢您的阅读。 订阅本站
Meng小羽
2021/06/29
4080
Python:变量的命名规则
2.不推荐使用以下划线开头,下划线开头的内容在python中有特殊意义,如_age,_name;
全栈程序员站长
2022/08/31
6950
第24天:js-函数变量声明提升
一、函数声明 1、自定义函数 function fun1(){ alert("我是自定义函数"); } fun2();//函数不调用,自己不执行 2、直接量声明 var fun2=function(){ alert("直接量声明"); } fun2(); 3、利用Function关键字声明 var fun3=new Function("var a=10;b=20;alert(a+b)"); fun3();
半指温柔乐
2018/09/11
1.8K0
Go - 变量声明
在声明变量之前,咱们先了解下变量的数据类型,这篇文章主要涉及 字符串、布尔、数字,其他类型后面开篇再说。
新亮
2019/07/08
1.2K0
Go - 变量声明

相似问题

在javascript中,应该在函数的顶部声明对象属性吗?

20

在C++中,应该在相应的头中声明局部变量吗?

30

应该在C++中内联声明函数的时间

10

当成员变量被构造函数参数初始化时,应该在声明中初始化它吗?

10

多行声明风格背后的原因?

40
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文