
mix.exs file to add ExMachina to the deps and application lists. To do this, simply insert another entry for ExMachina into the list of dependencies immediately after ComeOnIn: defp deps do [{:phoenix, "~> 1.2.0"}, {:phoenix_pubsub, "~> 1.0"}, {:phoenix_ecto, "~> 3.0"}, {:postgrex, ">= 0.0.0"}, {:phoenix_html, "~> 2.6"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, {:cowboy, "~> 1.0"}, {:comeonin, "~> 2.5.2"}, {:ex_machina, "~> 1.0"}] end :ex_machina to the list of used applications: def application do [mod: {Pxblog, []}, applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext, :phoenix_ecto, :postgrex, :comeonin, :ex_machina]] end $ mix do deps.get, compile mix test and make sure that all tests are green.test/support directory and then write its import in the tests we need.test/support/factory.ex file: defmodule Pxblog.Factory do use ExMachina.Ecto, repo: Pxblog.Repo alias Pxblog.Role alias Pxblog.User alias Pxblog.Post def role_factory do %Role{ name: sequence(:name, &"Test Role #{&1}"), admin: false } end end Factory because such a name reflects the essence of this module. Then we will use special factory functions. They compare with the sample an atom supplied to the input, which determines which type of factory to assemble / create . Since this library is pretty close to Factory Girl, it also brings with it some naming conventions that are important to know. The first such name will be build . The build function means that the model ( not the revision ) will be built without saving to the database. The second agreement will be the name of the insert function, which vice versa saves the model in the database, thereby creating it.use ExMachina.Ecto so that ExMachina uses Ecto as the Repo layer and behaves accordingly when creating models, associations, etc. We also need to add pseudonyms to all the models for which we will write factories.role_factory function should simply return a Role structure that defines default properties. This feature only supports arity 1.sequence function is pretty curious. We need to generate a unique name for each role. Therefore, we will make it sequentially generated. To do this, we take the function sequence , in which we pass two arguments: the first is the name of the field for which we want to generate a sequence, the second is an anonymous function, which returns a string and interpolates the value inside it. Let's take a look at this feature: &”Test Role #{&1}” fn x -> "Test Role #{x}" end sequence function can be explained this way: sequence(:name, fn x -> "Test Role #{x}" end) false , because we use this value as the default condition. We can create the administrative role by specifying this explicitly. Other more advanced features of ExMachina let's discuss a little later. Now we will spend some time combining our new factory Role with controller tests.test/controllers/user_controller_test.exs . At the top, in the setup block, add the use of our new function TestHelper.create_role : # ... import Pxblog.Factory @valid_create_attrs %{email: "test@test.com", username: "test", password: "test", password_confirmation: "test"} @valid_attrs %{email: "test@test.com", username: "test"} @invalid_attrs %{} setup do user_role = insert(:role) {:ok, nonadmin_user} = TestHelper.create_user(user_role, %{email: "nonadmin@test.com", username: "nonadmin", password: "test", password_confirmation: "test"}) admin_role = insert(:role, admin: true) {:ok, admin_user} = TestHelper.create_user(admin_role, %{email: "admin@test.com", username: "admin", password: "test", password_confirmation: "test"}) {:ok, conn: build_conn(), admin_role: admin_role, user_role: user_role, nonadmin_user: nonadmin_user, admin_user: admin_user} end # ... :role factory. In line 13, we do the same, but override the admin flag to true . def user_factory do %User{ username: sequence(:username, &"User #{&1}"), email: "test@test.com", password: "test1234", password_confirmation: "test1234", password_digest: Comeonin.Bcrypt.hashpwsalt("test1234"), role: build(:role) } end password_digest value to the password password hash value (as we simulate user login, we need to add this as well). We simply call the Bcrypt module from Comeonin and use the hashpwsalt function, passing the same value to it as in the password / password_confirmation fields. On the next line, we also set role as an association. We use the build function and pass in it the name of the association we want to build, in the form of an atom.test/controllers/user_controller_test.exs . setup do user_role = insert(:role) nonadmin_user = insert(:user, role: user_role) admin_role = insert(:role, admin: true) admin_user = insert(:user, role: admin_role) {:ok, conn: build_conn(), admin_role: admin_role, user_role: user_role, nonadmin_user: nonadmin_user, admin_user: admin_user} end TestHelper calls to the factory. We take the role and transfer it to the factory to create a user with the right role. Then, do the same with the administrator, but we don’t need to change our tests!test/controllers/post_controller_test.exs : def post_factory do %Post{ title: "Some Post", body: "And the body of some post", user: build(:user) } end import the Pxblog.Factory module Pxblog.Factory that our tests know where the factory is to which we send calls. Then we replace all the steps to create a post in the setup block with a factory call. Using the insert function, a role structure is created, which is then used to create a user through the factory, which is finally used to create the post associated with it ... Just something!TestHelper with Factory calls. This is not particularly new or exciting, so I will not pay undue attention to explaining the details.using block in the test/support/model_case.ex : using do quote do alias Pxblog.Repo import Ecto import Ecto.Changeset import Ecto.Query import Pxblog.ModelCase import Pxblog.Factory end end test/support/conn_case.ex : using do quote do # Import conveniences for testing with connections use Phoenix.ConnTest alias Pxblog.Repo import Ecto import Ecto.Changeset import Ecto.Query import Pxblog.Router.Helpers import Pxblog.Factory # The default endpoint for testing @endpoint Pxblog.Endpoint end end build and create there is support for some other functions for the sake of convenience (I use build as an example, but it also works with create ): build_pair(:factory, attrs) <- Builds 2 models build_list(n, :factory, attrs) <- Builds N models build method by calling create on it: build(:role) |> insert Source: https://habr.com/ru/post/316996/
All Articles