在開發(fā)用戶時,我們曾經(jīng)分章節(jié)完成各個屬性。但這里不再細(xì)分。
我們來看下 mix phx.gen.html
命令生成的 recipe_test.exs
文件內(nèi)容:
defmodule TvRecipe.RecipeTest do
use TvRecipe.ModelCase
alias TvRecipe.Recipe
@valid_attrs %{content: "some content", episode: 42, name: "some content", season: 42, title: "some content"}
@invalid_attrs %{}
test "changeset with valid attributes" do
changeset = Recipe.changeset(%Recipe{}, @valid_attrs)
assert changeset.valid?
end
test "changeset with invalid attributes" do
changeset = Recipe.changeset(%Recipe{}, @invalid_attrs)
refute changeset.valid?
end
end
很顯然,默認(rèn)生成的 @valid_attrs
是無效的,因為少了一個 user_id
。
但我們先處理其它屬性,因為比較簡單。
我們先增加測試:
diff --git a/test/tv_recipe/recipes/recipe_test.exs b/test/tv_recipe/recipes/recipe_test.exs
index a974aad..27f02ea 100644
--- a/test/tv_recipe/recipes/recipe_test.exs
+++ b/test/tv_recipe/recipes/recipe_test.exs
@@ -15,4 +15,29 @@ defmodule TvRecipe.RecipeTest do
changeset = Recipe.changeset(%Recipe{}, @invalid_attrs)
refute changeset.valid?
end
+
+ test "name is required" do
+ attrs = %{@valid_attrs | name: ""}
+ assert %{name: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
+ end
+
+ test "title is required" do
+ attrs = %{@valid_attrs | title: ""}
+ assert %{title: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
+ end
+
+ test "season is required" do
+ attrs = %{@valid_attrs | season: nil}
+ assert %{season: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
+ end
+
+ test "episode is required" do
+ attrs = %{@valid_attrs | episode: nil}
+ assert %{episode: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
+ end
+
+ test "season should greater than 0" do
+ attrs = %{@valid_attrs | season: 0}
+ assert %{season: ["請輸入大于 0 的數(shù)字"]} = errors_on(%Recipe{}, attrs)
+ end
+
+ test "episode should greater than 0" do
+ attrs = %{@valid_attrs | episode: 0}
+ assert %{episode: ["請輸入大于 0 的數(shù)字"]} = errors_on(%Recipe{}, attrs)
+ end
+
+ test "content is required" do
+ attrs = %{@valid_attrs | content: ""}
+ assert %{content: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
+ end
end
然后修改 recipe.ex
文件,自定義驗證消息:
diff --git a/web/models/recipe.ex b/web/models/recipe.ex
index 946d45c..8d34ed2 100644
--- a/web/models/recipe.ex
+++ b/web/models/recipe.ex
@@ -18,6 +18,6 @@ defmodule TvRecipe.Recipe do
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:name, :title, :season, :episode, :content])
- |> validate_required([:name, :title, :season, :episode, :content])
+ |> validate_required([:name, :title, :season, :episode, :content], message: "請?zhí)顚?)
+ |> validate_number(:season, greater_than: 0, message: "請輸入大于 0 的數(shù)字")
+ |> validate_number(:episode, greater_than: 0, message: "請輸入大于 0 的數(shù)字")
end
end
user_id
user_id
有兩條規(guī)則:
user_id
必填user_id
對應(yīng)著users
表中用戶的 id,該用戶在表中必須存在
必填
我們先處理 user_id
必填的規(guī)則,補(bǔ)充一個測試,如下:
diff --git a/test/tv_recipe/recipes/recipe_test.exs b/test/tv_recipe/recipes/recipe_test.exs
index 27f02ea..3a9630b 100644
--- a/test/tv_recipe/recipes/recipe_test.exs
+++ b/test/tv_recipe/recipes/recipe_test.exs
@@ -3,7 +3,7 @@ defmodule TvRecipe.RecipeTest do
alias TvRecipe..Recipes.Recipe
- @valid_attrs %{content: "some content", episode: 42, name: "some content", season: 42, title: "some content"}
+ @valid_attrs %{content: "some content", episode: 42, name: "some content", season: 42, title: "some content", user_id: 1}
@invalid_attrs %{}
test "changeset with valid attributes" do
@@ -40,4 +40,9 @@ defmodule TvRecipe.RecipeTest do
attrs = %{@valid_attrs | content: ""}
assert %{content: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
end
+
+ test "user_id is required" do
+ attrs = %{@valid_attrs | user_id: nil}
+ assert %{user_id: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
+ end
end
然后修改 recipe.ex
文件:
diff --git a/web/models/recipe.ex b/web/models/recipe.ex
index 8d34ed2..0520582 100644
--- a/web/models/recipe.ex
+++ b/web/models/recipe.ex
@@ -17,7 +17,7 @@ defmodule TvRecipe.Recipe do
"""
def changeset(struct, params \\ %{}) do
struct
- |> cast(params, [:name, :title, :season, :episode, :content])
- |> validate_required([:name, :title, :season, :episode, :content], message: "請?zhí)顚?)
+ |> cast(params, [:name, :title, :season, :episode, :content, :user_id])
+ |> validate_required([:name, :title, :season, :episode, :content, :user_id], message: "請?zhí)顚?)
end
end
運行新增的測試:
$ mix test test/tv_recipe/recipes/recipe_test.exs:54
Including tags: [line: "54"]
Excluding tags: [:test]
.
Finished in 0.1 seconds
10 tests, 0 failures, 9 skipped
注意,我們只測試前面新增的測試,:54
表示執(zhí)行該文件中第 54 行開始的 test
塊。
user_id
所指向的用戶應(yīng)存在
我們在 recipe_test.exs
文件中再增加一個測試,確保 user_id
所指的用戶存在:
diff --git a/test/tv_recipe/recipes/recipe_test.exs b/test/tv_recipe/recipes/recipe_test.exs
index 3a9630b..2e1191c 100644
--- a/test/tv_recipe/recipes/recipe_test.exs
+++ b/test/tv_recipe/recipes/recipe_test.exs
@@ -1,7 +1,7 @@
defmodule TvRecipe.RecipeTest do
use TvRecipe.ModelCase
- alias TvRecipe.Recipe
+ alias TvRecipe.Repo
+ alias TvRecipe.Recipes.Recipe
@valid_attrs %{content: "some content", episode: 42, name: "some content", season: 42, title: "some content", user_id: 1}
@invalid_attrs %{}
@@ -45,4 +45,9 @@ defmodule TvRecipe.RecipeTest do
attrs = %{@valid_attrs | user_id: nil}
assert %{user_id: ["請?zhí)顚?]} = errors_on(%Recipe{}, attrs)
end
+
+ test "user_id should exist in users table" do
+ {:error, changeset} = Repo.insert Recipe.changeset(%Recipe{}, @valid_attrs)
+ assert %{user_id: ["用戶不存在"]} = errors_on(changeset)
+ end
end
運行新增的測試:
$ mix test test/tv_recipe/recipes/recipe_test.exs:59
Compiling 13 files (.ex)
Including tags: [line: "59"]
Excluding tags: [:test]
1) test user_id should exist in users table (TvRecipe.RecipeTest)
test/tv_recipe/recipes/recipe_test.exs:59
** (Ecto.ConstraintError) constraint error when attempting to insert struct:
* foreign_key: recipes_user_id_fkey
If you would like to convert this constraint into an error, please
call foreign_key_constraint/3 in your changeset and define the proper
constraint name. The changeset has not defined any constraint.
stacktrace:
(ecto) lib/ecto/repo/schema.ex:493: anonymous fn/4 in Ecto.Repo.Schema.constraints_to_errors/3
(elixir) lib/enum.ex:1229: Enum."-map/2-lists^map/1-0-"/2
(ecto) lib/ecto/repo/schema.ex:479: Ecto.Repo.Schema.constraints_to_errors/3
(ecto) lib/ecto/repo/schema.ex:213: anonymous fn/13 in Ecto.Repo.Schema.do_insert/4
(ecto) lib/ecto/repo/schema.ex:684: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
(ecto) lib/ecto/adapters/sql.ex:615: anonymous fn/3 in Ecto.Adapters.SQL.do_transaction/3
(db_connection) lib/db_connection.ex:1274: DBConnection.transaction_run/4
(db_connection) lib/db_connection.ex:1198: DBConnection.run_begin/3
(db_connection) lib/db_connection.ex:789: DBConnection.transaction/3
test/tv_recipe/recipes/recipe_test.exs:60: (test)
Finished in 0.2 seconds
11 tests, 1 failure, 10 skipped
測試失敗,但 Phoenix 給了 foreign_key_constraint 的提示:
diff --git a/web/models/recipe.ex b/web/models/recipe.ex
index 0520582..a0b42fd 100644
--- a/web/models/recipe.ex
+++ b/web/models/recipe.ex
@@ -19,5 +19,6 @@ defmodule TvRecipe.Recipe do
struct
|> cast(params, [:name, :title, :season, :episode, :content, :user_id])
|> validate_required([:name, :title, :season, :episode, :content, :user_id], message: "請?zhí)顚?)
+ |> foreign_key_constraint(:user_id, message: "用戶不存在")
end
end
再次運行測試:
$ mix test test/tv_recipe/recipes/recipe_test.exs:59
Compiling 13 files (.ex)
Including tags: [line: "59"]
Excluding tags: [:test]
.
Finished in 0.1 seconds
11 tests, 0 failures, 10 skipped
測試通過。
但我們運行所有測試的話:
$ mix test
..........................................
1) test creates resource and redirects when data is valid (TvRecipe.RecipeControllerTest)
test/controllers/recipe_controller_test.exs:18
** (RuntimeError) expected redirection with status 302, got: 200
stacktrace:
(phoenix) lib/phoenix/test/conn_test.ex:443: Phoenix.ConnTest.redirected_to/2
test/controllers/recipe_controller_test.exs:20: (test)
2) test updates chosen resource and redirects when data is valid (TvRecipe.RecipeControllerTest)
test/controllers/recipe_controller_test.exs:47
** (RuntimeError) expected redirection with status 302, got: 200
stacktrace:
(phoenix) lib/phoenix/test/conn_test.ex:443: Phoenix.ConnTest.redirected_to/2
test/controllers/recipe_controller_test.exs:50: (test)
..........
Finished in 0.6 seconds
56 tests, 2 failures
recipe_controller_test.exs
文件中出現(xiàn)兩個錯誤 - 不過我們留給下一章處理。
更多建議: